All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 00/27] iommu: support txattrs, support TCG execution, implement TZ MPC
@ 2018-05-21 14:03 Peter Maydell
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 01/27] memory.h: Improve IOMMU related documentation Peter Maydell
                   ` (28 more replies)
  0 siblings, 29 replies; 114+ messages in thread
From: Peter Maydell @ 2018-05-21 14:03 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: patches, Paolo Bonzini, Richard Henderson, Alex Bennée

This patchset is a rather large one, but the first half is all
fairly simple plumbing. It does four things:
 * support IOMMUs that are aware of memory transaction attributes and
   may generate different translations for different attributes
 * support TCG execution out of memory which is behind an IOMMU
 * implement the Arm TrustZone Memory Protection Controller
   (which needs both the above features in the IOMMU core code)
 * use the MPC in the mps2-an505 board

I'm happy to split this up (eg taking the IOMMU core code
changes through Paolo's tree and then the MPS stuff via
target-arm), but I figured it would be useful to see the
reason and the user of the new APIs in the same series.


Patch 1 is my "improve the IOMMU API documentation" patch (included
here because otherwise the added API documentation for new methods
would conflict).

Patches 2-13 are the boring plumbing: we pass down MemTxAttrs
through enough of the memory subsystem that we have access to
them at the point where we call the IOMMU translate method.
(A previous version of these was posted separately; I've rebased
them and updated to account for new changes in the code since then,
but the general principles remain the same.)

Patches 14, 15 and 16 add the support for memory-transaction-aware
IOMMUs. The general approach is that we have the concept of an
IOMMU index (similar to the TCG MMU index), which selects which of
multiple possible translation tables in the IOMMU we're trying to use.
Most IOMMUs will support just a single index. When you register an
IOMMU notifier and when you call the translate method you have to
specify which IOMMU index you want. There's a method for getting the
index that applies for a particular set of transaction attributes.
All the current IOMMU implementations have just one iommu index, and
all the current users of the notify API assume that.

Patch 17 adds the support for TCG execution from memory that sits
behind an IOMMU. We do this in a fairly simple way on the assumption
that changes to the IOMMU config at runtime will be fairly uncommon:
we just flush the CPU TLB so it forgets about any cached results
when we get an IOMMU unmap notification. (This is similar to how
we handle reconfigurations of the memory map done by mapping or
unmapping MemoryRegions.) NB: I'm not completely sure that calling
tlb_flush() here is sufficient to be non-racy in the case where CPU A
has triggered the IOMMU unmap notify by changing the IOMMU config
while CPU B is executing from memory behind the IOMMU, but tlb_flush()
is what tcg_commit() uses so I guess it's OK. I think the idea here
is that any delay in flushing B's TLB is just equivalent to B having
executed a little bit further before A got to changing the config?

Patches 18-21 implement the TrustZone Memory Protection Controller,
which is a fairly simple piece of hardware that just configurably
either allows or blocks transactions depending on attrs.secure.

Patches 22 and 23 deal with a limitation in our or-irq device, which
currently only allows 16 input lines (we need 17 for one of the OR
gates in the IoTKit object). The patches raise the limit to 32, but
in a way that means we can easily raise it further in future without
migration compatibility problems.

Patches 24-27 add MPCs to the IoTKit SoC object and to the mps2-an505
board model, and wire them up appropriately.

Based-on: 20180518153157.14899-1-peter.maydell@linaro.org
[MAINTAINERS: Add entries for newer MPS2 boards and devices]
purely to avoid the textual conflict when we add MAINTAINERS entries




Peter Maydell (27):
  memory.h: Improve IOMMU related documentation
  Make tb_invalidate_phys_addr() take a MemTxAttrs argument
  Make address_space_translate{,_cached}() take a MemTxAttrs argument
  Make address_space_map() take a MemTxAttrs argument
  Make address_space_access_valid() take a MemTxAttrs argument
  Make flatview_extend_translation() take a MemTxAttrs argument
  Make memory_region_access_valid() take a MemTxAttrs argument
  Make MemoryRegion valid.accepts callback take a MemTxAttrs argument
  Make flatview_access_valid() take a MemTxAttrs argument
  Make flatview_translate() take a MemTxAttrs argument
  Make address_space_get_iotlb_entry() take a MemTxAttrs argument
  Make flatview_do_translate() take a MemTxAttrs argument
  Make address_space_translate_iommu take a MemTxAttrs argument
  iommu: Add IOMMU index concept to IOMMU API
  iommu: Add IOMMU index argument to notifier APIs
  iommu: Add IOMMU index argument to translate method
  exec.c: Handle IOMMUs in address_space_translate_for_iotlb()
  hw/misc/tz-mpc.c: Implement the Arm TrustZone Memory Protection
    Controller
  hw/misc/tz-mpc.c: Implement registers
  hw/misc/tz-mpc.c: Implement correct blocked-access behaviour
  hw/misc/tz_mpc.c: Honour the BLK_LUT settings in translate
  vmstate.h: Provide VMSTATE_BOOL_SUB_ARRAY
  hw/core/or-irq: Support more than 16 inputs to an OR gate
  hw/misc/iotkit-secctl.c: Implement SECMPCINTSTATUS
  hw/arm/iotkit: Instantiate MPC
  hw/arm/iotkit: Wire up MPC interrupt lines
  hw/arm/mps2-tz.c: Instantiate MPCs

 hw/misc/Makefile.objs           |   1 +
 include/exec/exec-all.h         |   8 +-
 include/exec/memory-internal.h  |   3 +-
 include/exec/memory.h           | 194 ++++++++--
 include/hw/arm/iotkit.h         |   8 +
 include/hw/misc/iotkit-secctl.h |   8 +
 include/hw/misc/tz-mpc.h        |  80 +++++
 include/hw/or-irq.h             |   5 +-
 include/migration/vmstate.h     |   3 +
 include/qom/cpu.h               |   3 +
 include/sysemu/dma.h            |   6 +-
 accel/tcg/cputlb.c              |   3 +-
 accel/tcg/translate-all.c       |   4 +-
 exec.c                          | 254 +++++++++++---
 hw/alpha/typhoon.c              |   3 +-
 hw/arm/iotkit.c                 | 112 +++++-
 hw/arm/mps2-tz.c                |  71 ++--
 hw/arm/smmuv3.c                 |   2 +-
 hw/core/or-irq.c                |  39 ++-
 hw/dma/rc4030.c                 |   2 +-
 hw/hppa/dino.c                  |   3 +-
 hw/i386/amd_iommu.c             |   2 +-
 hw/i386/intel_iommu.c           |   6 +-
 hw/misc/iotkit-secctl.c         |  38 +-
 hw/misc/tz-mpc.c                | 604 ++++++++++++++++++++++++++++++++
 hw/nvram/fw_cfg.c               |  12 +-
 hw/ppc/spapr_iommu.c            |   5 +-
 hw/s390x/s390-pci-bus.c         |   2 +-
 hw/s390x/s390-pci-inst.c        |   7 +-
 hw/scsi/esp.c                   |   3 +-
 hw/sparc/sun4m_iommu.c          |   3 +-
 hw/sparc64/sun4u_iommu.c        |   2 +-
 hw/vfio/common.c                |   9 +-
 hw/virtio/vhost.c               |  10 +-
 hw/xen/xen_pt_msi.c             |   3 +-
 memory.c                        |  45 ++-
 memory_ldst.inc.c               |  18 +-
 target/ppc/mmu-hash64.c         |   3 +-
 target/riscv/helper.c           |   2 +-
 target/s390x/diag.c             |   6 +-
 target/s390x/excp_helper.c      |   3 +-
 target/s390x/mmu_helper.c       |   3 +-
 target/s390x/sigp.c             |   3 +-
 target/xtensa/op_helper.c       |   3 +-
 MAINTAINERS                     |   2 +
 default-configs/arm-softmmu.mak |   1 +
 hw/misc/trace-events            |   8 +
 47 files changed, 1452 insertions(+), 163 deletions(-)
 create mode 100644 include/hw/misc/tz-mpc.h
 create mode 100644 hw/misc/tz-mpc.c

-- 
2.17.0

^ permalink raw reply	[flat|nested] 114+ messages in thread

* [Qemu-devel] [PATCH 01/27] memory.h: Improve IOMMU related documentation
  2018-05-21 14:03 [Qemu-devel] [PATCH 00/27] iommu: support txattrs, support TCG execution, implement TZ MPC Peter Maydell
@ 2018-05-21 14:03 ` Peter Maydell
  2018-05-21 19:46   ` Richard Henderson
                     ` (2 more replies)
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 02/27] Make tb_invalidate_phys_addr() take a MemTxAttrs argument Peter Maydell
                   ` (27 subsequent siblings)
  28 siblings, 3 replies; 114+ messages in thread
From: Peter Maydell @ 2018-05-21 14:03 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: patches, Paolo Bonzini, Richard Henderson, Alex Bennée

Add more detail to the documentation for memory_region_init_iommu()
and other IOMMU-related functions and data structures.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
v2->v3 changes:
 * minor wording tweaks per Eric's review
 * moved the bit about requirements to notify out from the translate
   method docs to the top level class doc comment
 * added description of flags argument and in particular that it's
   just an optimization and callers can pass IOMMU_NONE to get the
   full permissions
v1 -> v2 changes:
 * documented replay method
 * added note about wanting RCU or big qemu lock while calling
   translate
---
 include/exec/memory.h | 105 ++++++++++++++++++++++++++++++++++++++----
 1 file changed, 95 insertions(+), 10 deletions(-)

diff --git a/include/exec/memory.h b/include/exec/memory.h
index 4fa1227f13..cce355d2d8 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -194,29 +194,100 @@ enum IOMMUMemoryRegionAttr {
     IOMMU_ATTR_SPAPR_TCE_FD
 };
 
+/**
+ * IOMMUMemoryRegionClass:
+ *
+ * All IOMMU implementations need to subclass TYPE_IOMMU_MEMORY_REGION
+ * and provide an implementation of at least the @translate method here
+ * to handle requests to the memory region. Other methods are optional.
+ *
+ * The IOMMU implementation must use the IOMMU notifier infrastructure
+ * to report whenever mappings are changed, by calling
+ * memory_region_notify_iommu() (or, if necessary, by calling
+ * memory_region_notify_one() for each registered notifier).
+ */
 typedef struct IOMMUMemoryRegionClass {
     /* private */
     struct DeviceClass parent_class;
 
     /*
-     * Return a TLB entry that contains a given address. Flag should
-     * be the access permission of this translation operation. We can
-     * set flag to IOMMU_NONE to mean that we don't need any
-     * read/write permission checks, like, when for region replay.
+     * Return a TLB entry that contains a given address.
+     *
+     * The IOMMUAccessFlags indicated via @flag are optional and may
+     * be specified as IOMMU_NONE to indicate that the caller needs
+     * the full translation information for both reads and writes. If
+     * the access flags are specified then the IOMMU implementation
+     * may use this as an optimization, to stop doing a page table
+     * walk as soon as it knows that the requested permissions are not
+     * allowed. If IOMMU_NONE is passed then the IOMMU must do the
+     * full page table walk and report the permissions in the returned
+     * IOMMUTLBEntry. (Note that this implies that an IOMMU may not
+     * return different mappings for reads and writes.)
+     *
+     * The returned information remains valid while the caller is
+     * holding the big QEMU lock or is inside an RCU critical section;
+     * if the caller wishes to cache the mapping beyond that it must
+     * register an IOMMU notifier so it can invalidate its cached
+     * information when the IOMMU mapping changes.
+     *
+     * @iommu: the IOMMUMemoryRegion
+     * @hwaddr: address to be translated within the memory region
+     * @flag: requested access permissions
      */
     IOMMUTLBEntry (*translate)(IOMMUMemoryRegion *iommu, hwaddr addr,
                                IOMMUAccessFlags flag);
-    /* Returns minimum supported page size */
+    /* Returns minimum supported page size in bytes.
+     * If this method is not provided then the minimum is assumed to
+     * be TARGET_PAGE_SIZE.
+     *
+     * @iommu: the IOMMUMemoryRegion
+     */
     uint64_t (*get_min_page_size)(IOMMUMemoryRegion *iommu);
-    /* Called when IOMMU Notifier flag changed */
+    /* Called when IOMMU Notifier flag changes (ie when the set of
+     * events which IOMMU users are requesting notification for changes).
+     * Optional method -- need not be provided if the IOMMU does not
+     * need to know exactly which events must be notified.
+     *
+     * @iommu: the IOMMUMemoryRegion
+     * @old_flags: events which previously needed to be notified
+     * @new_flags: events which now need to be notified
+     */
     void (*notify_flag_changed)(IOMMUMemoryRegion *iommu,
                                 IOMMUNotifierFlag old_flags,
                                 IOMMUNotifierFlag new_flags);
-    /* Set this up to provide customized IOMMU replay function */
+    /* Called to handle memory_region_iommu_replay().
+     *
+     * The default implementation of memory_region_iommu_replay() is to
+     * call the IOMMU translate method for every page in the address space
+     * with flag == IOMMU_NONE and then call the notifier if translate
+     * returns a valid mapping. If this method is implemented then it
+     * overrides the default behaviour, and must provide the full semantics
+     * of memory_region_iommu_replay(), by calling @notifier for every
+     * translation present in the IOMMU.
+     *
+     * Optional method -- an IOMMU only needs to provide this method
+     * if the default is inefficient or produces undesirable side effects.
+     *
+     * Note: this is not related to record-and-replay functionality.
+     */
     void (*replay)(IOMMUMemoryRegion *iommu, IOMMUNotifier *notifier);
 
-    /* Get IOMMU misc attributes */
-    int (*get_attr)(IOMMUMemoryRegion *iommu, enum IOMMUMemoryRegionAttr,
+    /* Get IOMMU misc attributes. This is an optional method that
+     * can be used to allow users of the IOMMU to get implementation-specific
+     * information. The IOMMU implements this method to handle calls
+     * by IOMMU users to memory_region_iommu_get_attr() by filling in
+     * the arbitrary data pointer for any IOMMUMemoryRegionAttr values that
+     * the IOMMU supports. If the method is unimplemented then
+     * memory_region_iommu_get_attr() will always return -EINVAL.
+     *
+     * @iommu: the IOMMUMemoryRegion
+     * @attr: attribute being queried
+     * @data: memory to fill in with the attribute data
+     *
+     * Returns 0 on success, or a negative errno; in particular
+     * returns -EINVAL for unrecognized or unimplemented attribute types.
+     */
+    int (*get_attr)(IOMMUMemoryRegion *iommu, enum IOMMUMemoryRegionAttr attr,
                     void *data);
 } IOMMUMemoryRegionClass;
 
@@ -705,6 +776,14 @@ static inline void memory_region_init_reservation(MemoryRegion *mr,
  * An IOMMU region translates addresses and forwards accesses to a target
  * memory region.
  *
+ * The IOMMU implementation must define a subclass of TYPE_IOMMU_MEMORY_REGION.
+ * @_iommu_mr should be a pointer to enough memory for an instance of
+ * that subclass, @instance_size is the size of that subclass, and
+ * @mrtypename is its name. This function will initialize @_iommu_mr as an
+ * instance of the subclass, and its methods will then be called to handle
+ * accesses to the memory region. See the documentation of
+ * #IOMMUMemoryRegionClass for further details.
+ *
  * @_iommu_mr: the #IOMMUMemoryRegion to be initialized
  * @instance_size: the IOMMUMemoryRegion subclass instance size
  * @mrtypename: the type name of the #IOMMUMemoryRegion
@@ -953,6 +1032,8 @@ void memory_region_register_iommu_notifier(MemoryRegion *mr,
  * a notifier with the minimum page granularity returned by
  * mr->iommu_ops->get_page_size().
  *
+ * Note: this is not related to record-and-replay functionality.
+ *
  * @iommu_mr: the memory region to observe
  * @n: the notifier to which to replay iommu mappings
  */
@@ -962,6 +1043,8 @@ void memory_region_iommu_replay(IOMMUMemoryRegion *iommu_mr, IOMMUNotifier *n);
  * memory_region_iommu_replay_all: replay existing IOMMU translations
  * to all the notifiers registered.
  *
+ * Note: this is not related to record-and-replay functionality.
+ *
  * @iommu_mr: the memory region to observe
  */
 void memory_region_iommu_replay_all(IOMMUMemoryRegion *iommu_mr);
@@ -981,7 +1064,9 @@ void memory_region_unregister_iommu_notifier(MemoryRegion *mr,
  * memory_region_iommu_get_attr: return an IOMMU attr if get_attr() is
  * defined on the IOMMU.
  *
- * Returns 0 if succeded, error code otherwise.
+ * Returns 0 on success, or a negative errno otherwise. In particular,
+ * -EINVAL indicates that the IOMMU does not support the requested
+ * attribute.
  *
  * @iommu_mr: the memory region
  * @attr: the requested attribute
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [Qemu-devel] [PATCH 02/27] Make tb_invalidate_phys_addr() take a MemTxAttrs argument
  2018-05-21 14:03 [Qemu-devel] [PATCH 00/27] iommu: support txattrs, support TCG execution, implement TZ MPC Peter Maydell
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 01/27] memory.h: Improve IOMMU related documentation Peter Maydell
@ 2018-05-21 14:03 ` Peter Maydell
  2018-05-21 23:54   ` Richard Henderson
  2018-05-22  9:21   ` Alex Bennée
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 03/27] Make address_space_translate{, _cached}() " Peter Maydell
                   ` (26 subsequent siblings)
  28 siblings, 2 replies; 114+ messages in thread
From: Peter Maydell @ 2018-05-21 14:03 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: patches, Paolo Bonzini, Richard Henderson, Alex Bennée

As part of plumbing MemTxAttrs down to the IOMMU translate method,
add MemTxAttrs as an argument to tb_invalidate_phys_addr().
Its callers either have an attrs value to hand, or don't care
and can use MEMTXATTRS_UNSPECIFIED.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 include/exec/exec-all.h   | 5 +++--
 accel/tcg/translate-all.c | 2 +-
 exec.c                    | 2 +-
 target/xtensa/op_helper.c | 3 ++-
 4 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
index bd68328ed9..4d09eaba72 100644
--- a/include/exec/exec-all.h
+++ b/include/exec/exec-all.h
@@ -255,7 +255,7 @@ void tlb_set_page_with_attrs(CPUState *cpu, target_ulong vaddr,
 void tlb_set_page(CPUState *cpu, target_ulong vaddr,
                   hwaddr paddr, int prot,
                   int mmu_idx, target_ulong size);
-void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr);
+void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr, MemTxAttrs attrs);
 void probe_write(CPUArchState *env, target_ulong addr, int size, int mmu_idx,
                  uintptr_t retaddr);
 #else
@@ -303,7 +303,8 @@ static inline void tlb_flush_by_mmuidx_all_cpus_synced(CPUState *cpu,
                                                        uint16_t idxmap)
 {
 }
-static inline void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr)
+static inline void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr,
+                                           MemTxAttrs attrs)
 {
 }
 #endif
diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
index f409d42d54..f04a922ef7 100644
--- a/accel/tcg/translate-all.c
+++ b/accel/tcg/translate-all.c
@@ -1672,7 +1672,7 @@ static TranslationBlock *tb_find_pc(uintptr_t tc_ptr)
 }
 
 #if !defined(CONFIG_USER_ONLY)
-void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr)
+void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr, MemTxAttrs attrs)
 {
     ram_addr_t ram_addr;
     MemoryRegion *mr;
diff --git a/exec.c b/exec.c
index ffa1099547..c3a197e67b 100644
--- a/exec.c
+++ b/exec.c
@@ -898,7 +898,7 @@ static void breakpoint_invalidate(CPUState *cpu, target_ulong pc)
     if (phys != -1) {
         /* Locks grabbed by tb_invalidate_phys_addr */
         tb_invalidate_phys_addr(cpu->cpu_ases[asidx].as,
-                                phys | (pc & ~TARGET_PAGE_MASK));
+                                phys | (pc & ~TARGET_PAGE_MASK), attrs);
     }
 }
 #endif
diff --git a/target/xtensa/op_helper.c b/target/xtensa/op_helper.c
index e3bcbe10d6..8a8c763c63 100644
--- a/target/xtensa/op_helper.c
+++ b/target/xtensa/op_helper.c
@@ -105,7 +105,8 @@ static void tb_invalidate_virtual_addr(CPUXtensaState *env, uint32_t vaddr)
     int ret = xtensa_get_physical_addr(env, false, vaddr, 2, 0,
             &paddr, &page_size, &access);
     if (ret == 0) {
-        tb_invalidate_phys_addr(&address_space_memory, paddr);
+        tb_invalidate_phys_addr(&address_space_memory, paddr,
+                                MEMTXATTRS_UNSPECIFIED);
     }
 }
 
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [Qemu-devel] [PATCH 03/27] Make address_space_translate{, _cached}() take a MemTxAttrs argument
  2018-05-21 14:03 [Qemu-devel] [PATCH 00/27] iommu: support txattrs, support TCG execution, implement TZ MPC Peter Maydell
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 01/27] memory.h: Improve IOMMU related documentation Peter Maydell
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 02/27] Make tb_invalidate_phys_addr() take a MemTxAttrs argument Peter Maydell
@ 2018-05-21 14:03 ` Peter Maydell
  2018-05-22 10:49   ` Alex Bennée
  2018-05-22 16:12   ` Richard Henderson
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 04/27] Make address_space_map() " Peter Maydell
                   ` (25 subsequent siblings)
  28 siblings, 2 replies; 114+ messages in thread
From: Peter Maydell @ 2018-05-21 14:03 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: patches, Paolo Bonzini, Richard Henderson, Alex Bennée

As part of plumbing MemTxAttrs down to the IOMMU translate method,
add MemTxAttrs as an argument to address_space_translate()
and address_space_translate_cached(). Callers either have an
attrs value to hand, or don't care and can use MEMTXATTRS_UNSPECIFIED.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 include/exec/memory.h     |  4 +++-
 accel/tcg/translate-all.c |  2 +-
 exec.c                    | 14 +++++++++-----
 hw/vfio/common.c          |  3 ++-
 memory_ldst.inc.c         | 18 +++++++++---------
 target/riscv/helper.c     |  2 +-
 6 files changed, 25 insertions(+), 18 deletions(-)

diff --git a/include/exec/memory.h b/include/exec/memory.h
index cce355d2d8..9a30a1bb9e 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -1908,6 +1908,7 @@ IOMMUTLBEntry address_space_get_iotlb_entry(AddressSpace *as, hwaddr addr,
  * #MemoryRegion.
  * @len: pointer to length
  * @is_write: indicates the transfer direction
+ * @attrs: memory attributes
  */
 MemoryRegion *flatview_translate(FlatView *fv,
                                  hwaddr addr, hwaddr *xlat,
@@ -1915,7 +1916,8 @@ MemoryRegion *flatview_translate(FlatView *fv,
 
 static inline MemoryRegion *address_space_translate(AddressSpace *as,
                                                     hwaddr addr, hwaddr *xlat,
-                                                    hwaddr *len, bool is_write)
+                                                    hwaddr *len, bool is_write,
+                                                    MemTxAttrs attrs)
 {
     return flatview_translate(address_space_to_flatview(as),
                               addr, xlat, len, is_write);
diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
index f04a922ef7..52f7bd59a9 100644
--- a/accel/tcg/translate-all.c
+++ b/accel/tcg/translate-all.c
@@ -1679,7 +1679,7 @@ void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr, MemTxAttrs attrs)
     hwaddr l = 1;
 
     rcu_read_lock();
-    mr = address_space_translate(as, addr, &addr, &l, false);
+    mr = address_space_translate(as, addr, &addr, &l, false, attrs);
     if (!(memory_region_is_ram(mr)
           || memory_region_is_romd(mr))) {
         rcu_read_unlock();
diff --git a/exec.c b/exec.c
index c3a197e67b..d314c7cc39 100644
--- a/exec.c
+++ b/exec.c
@@ -3322,7 +3322,8 @@ static inline void cpu_physical_memory_write_rom_internal(AddressSpace *as,
     rcu_read_lock();
     while (len > 0) {
         l = len;
-        mr = address_space_translate(as, addr, &addr1, &l, true);
+        mr = address_space_translate(as, addr, &addr1, &l, true,
+                                     MEMTXATTRS_UNSPECIFIED);
 
         if (!(memory_region_is_ram(mr) ||
               memory_region_is_romd(mr))) {
@@ -3699,7 +3700,7 @@ void address_space_cache_destroy(MemoryRegionCache *cache)
  */
 static inline MemoryRegion *address_space_translate_cached(
     MemoryRegionCache *cache, hwaddr addr, hwaddr *xlat,
-    hwaddr *plen, bool is_write)
+    hwaddr *plen, bool is_write, MemTxAttrs attrs)
 {
     MemoryRegionSection section;
     MemoryRegion *mr;
@@ -3733,7 +3734,8 @@ address_space_read_cached_slow(MemoryRegionCache *cache, hwaddr addr,
     MemoryRegion *mr;
 
     l = len;
-    mr = address_space_translate_cached(cache, addr, &addr1, &l, false);
+    mr = address_space_translate_cached(cache, addr, &addr1, &l, false,
+                                        MEMTXATTRS_UNSPECIFIED);
     flatview_read_continue(cache->fv,
                            addr, MEMTXATTRS_UNSPECIFIED, buf, len,
                            addr1, l, mr);
@@ -3750,7 +3752,8 @@ address_space_write_cached_slow(MemoryRegionCache *cache, hwaddr addr,
     MemoryRegion *mr;
 
     l = len;
-    mr = address_space_translate_cached(cache, addr, &addr1, &l, true);
+    mr = address_space_translate_cached(cache, addr, &addr1, &l, true,
+                                        MEMTXATTRS_UNSPECIFIED);
     flatview_write_continue(cache->fv,
                             addr, MEMTXATTRS_UNSPECIFIED, buf, len,
                             addr1, l, mr);
@@ -3848,7 +3851,8 @@ bool cpu_physical_memory_is_io(hwaddr phys_addr)
 
     rcu_read_lock();
     mr = address_space_translate(&address_space_memory,
-                                 phys_addr, &phys_addr, &l, false);
+                                 phys_addr, &phys_addr, &l, false,
+                                 MEMTXATTRS_UNSPECIFIED);
 
     res = !(memory_region_is_ram(mr) || memory_region_is_romd(mr));
     rcu_read_unlock();
diff --git a/hw/vfio/common.c b/hw/vfio/common.c
index 07ffa0ba10..8e57265edf 100644
--- a/hw/vfio/common.c
+++ b/hw/vfio/common.c
@@ -324,7 +324,8 @@ static bool vfio_get_vaddr(IOMMUTLBEntry *iotlb, void **vaddr,
      */
     mr = address_space_translate(&address_space_memory,
                                  iotlb->translated_addr,
-                                 &xlat, &len, writable);
+                                 &xlat, &len, writable,
+                                 MEMTXATTRS_UNSPECIFIED);
     if (!memory_region_is_ram(mr)) {
         error_report("iommu map to non memory area %"HWADDR_PRIx"",
                      xlat);
diff --git a/memory_ldst.inc.c b/memory_ldst.inc.c
index 25d6125747..15483987fe 100644
--- a/memory_ldst.inc.c
+++ b/memory_ldst.inc.c
@@ -33,7 +33,7 @@ static inline uint32_t glue(address_space_ldl_internal, SUFFIX)(ARG1_DECL,
     bool release_lock = false;
 
     RCU_READ_LOCK();
-    mr = TRANSLATE(addr, &addr1, &l, false);
+    mr = TRANSLATE(addr, &addr1, &l, false, attrs);
     if (l < 4 || !IS_DIRECT(mr, false)) {
         release_lock |= prepare_mmio_access(mr);
 
@@ -109,7 +109,7 @@ static inline uint64_t glue(address_space_ldq_internal, SUFFIX)(ARG1_DECL,
     bool release_lock = false;
 
     RCU_READ_LOCK();
-    mr = TRANSLATE(addr, &addr1, &l, false);
+    mr = TRANSLATE(addr, &addr1, &l, false, attrs);
     if (l < 8 || !IS_DIRECT(mr, false)) {
         release_lock |= prepare_mmio_access(mr);
 
@@ -183,7 +183,7 @@ uint32_t glue(address_space_ldub, SUFFIX)(ARG1_DECL,
     bool release_lock = false;
 
     RCU_READ_LOCK();
-    mr = TRANSLATE(addr, &addr1, &l, false);
+    mr = TRANSLATE(addr, &addr1, &l, false, attrs);
     if (!IS_DIRECT(mr, false)) {
         release_lock |= prepare_mmio_access(mr);
 
@@ -219,7 +219,7 @@ static inline uint32_t glue(address_space_lduw_internal, SUFFIX)(ARG1_DECL,
     bool release_lock = false;
 
     RCU_READ_LOCK();
-    mr = TRANSLATE(addr, &addr1, &l, false);
+    mr = TRANSLATE(addr, &addr1, &l, false, attrs);
     if (l < 2 || !IS_DIRECT(mr, false)) {
         release_lock |= prepare_mmio_access(mr);
 
@@ -296,7 +296,7 @@ void glue(address_space_stl_notdirty, SUFFIX)(ARG1_DECL,
     bool release_lock = false;
 
     RCU_READ_LOCK();
-    mr = TRANSLATE(addr, &addr1, &l, true);
+    mr = TRANSLATE(addr, &addr1, &l, true, attrs);
     if (l < 4 || !IS_DIRECT(mr, true)) {
         release_lock |= prepare_mmio_access(mr);
 
@@ -333,7 +333,7 @@ static inline void glue(address_space_stl_internal, SUFFIX)(ARG1_DECL,
     bool release_lock = false;
 
     RCU_READ_LOCK();
-    mr = TRANSLATE(addr, &addr1, &l, true);
+    mr = TRANSLATE(addr, &addr1, &l, true, attrs);
     if (l < 4 || !IS_DIRECT(mr, true)) {
         release_lock |= prepare_mmio_access(mr);
 
@@ -405,7 +405,7 @@ void glue(address_space_stb, SUFFIX)(ARG1_DECL,
     bool release_lock = false;
 
     RCU_READ_LOCK();
-    mr = TRANSLATE(addr, &addr1, &l, true);
+    mr = TRANSLATE(addr, &addr1, &l, true, attrs);
     if (!IS_DIRECT(mr, true)) {
         release_lock |= prepare_mmio_access(mr);
         r = memory_region_dispatch_write(mr, addr1, val, 1, attrs);
@@ -438,7 +438,7 @@ static inline void glue(address_space_stw_internal, SUFFIX)(ARG1_DECL,
     bool release_lock = false;
 
     RCU_READ_LOCK();
-    mr = TRANSLATE(addr, &addr1, &l, true);
+    mr = TRANSLATE(addr, &addr1, &l, true, attrs);
     if (l < 2 || !IS_DIRECT(mr, true)) {
         release_lock |= prepare_mmio_access(mr);
 
@@ -511,7 +511,7 @@ static void glue(address_space_stq_internal, SUFFIX)(ARG1_DECL,
     bool release_lock = false;
 
     RCU_READ_LOCK();
-    mr = TRANSLATE(addr, &addr1, &l, true);
+    mr = TRANSLATE(addr, &addr1, &l, true, attrs);
     if (l < 8 || !IS_DIRECT(mr, true)) {
         release_lock |= prepare_mmio_access(mr);
 
diff --git a/target/riscv/helper.c b/target/riscv/helper.c
index 95889f23b9..29e1a603dc 100644
--- a/target/riscv/helper.c
+++ b/target/riscv/helper.c
@@ -210,7 +210,7 @@ restart:
                 MemoryRegion *mr;
                 hwaddr l = sizeof(target_ulong), addr1;
                 mr = address_space_translate(cs->as, pte_addr,
-                    &addr1, &l, false);
+                    &addr1, &l, false, MEMTXATTRS_UNSPECIFIED);
                 if (memory_access_is_direct(mr, true)) {
                     target_ulong *pte_pa =
                         qemu_map_ram_ptr(mr->ram_block, addr1);
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [Qemu-devel] [PATCH 04/27] Make address_space_map() take a MemTxAttrs argument
  2018-05-21 14:03 [Qemu-devel] [PATCH 00/27] iommu: support txattrs, support TCG execution, implement TZ MPC Peter Maydell
                   ` (2 preceding siblings ...)
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 03/27] Make address_space_translate{, _cached}() " Peter Maydell
@ 2018-05-21 14:03 ` Peter Maydell
  2018-05-22 10:49   ` Alex Bennée
  2018-05-22 16:13   ` Richard Henderson
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 05/27] Make address_space_access_valid() " Peter Maydell
                   ` (24 subsequent siblings)
  28 siblings, 2 replies; 114+ messages in thread
From: Peter Maydell @ 2018-05-21 14:03 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: patches, Paolo Bonzini, Richard Henderson, Alex Bennée

As part of plumbing MemTxAttrs down to the IOMMU translate method,
add MemTxAttrs as an argument to address_space_map().
Its callers either have an attrs value to hand, or don't care
and can use MEMTXATTRS_UNSPECIFIED.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 include/exec/memory.h   | 3 ++-
 include/sysemu/dma.h    | 3 ++-
 exec.c                  | 6 ++++--
 target/ppc/mmu-hash64.c | 3 ++-
 4 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/include/exec/memory.h b/include/exec/memory.h
index 9a30a1bb9e..b1bdb376d4 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -1952,9 +1952,10 @@ bool address_space_access_valid(AddressSpace *as, hwaddr addr, int len, bool is_
  * @addr: address within that address space
  * @plen: pointer to length of buffer; updated on return
  * @is_write: indicates the transfer direction
+ * @attrs: memory attributes
  */
 void *address_space_map(AddressSpace *as, hwaddr addr,
-                        hwaddr *plen, bool is_write);
+                        hwaddr *plen, bool is_write, MemTxAttrs attrs);
 
 /* address_space_unmap: Unmaps a memory region previously mapped by address_space_map()
  *
diff --git a/include/sysemu/dma.h b/include/sysemu/dma.h
index c228c66513..0d73902634 100644
--- a/include/sysemu/dma.h
+++ b/include/sysemu/dma.h
@@ -132,7 +132,8 @@ static inline void *dma_memory_map(AddressSpace *as,
     hwaddr xlen = *len;
     void *p;
 
-    p = address_space_map(as, addr, &xlen, dir == DMA_DIRECTION_FROM_DEVICE);
+    p = address_space_map(as, addr, &xlen, dir == DMA_DIRECTION_FROM_DEVICE,
+                          MEMTXATTRS_UNSPECIFIED);
     *len = xlen;
     return p;
 }
diff --git a/exec.c b/exec.c
index d314c7cc39..1dc81cfe4a 100644
--- a/exec.c
+++ b/exec.c
@@ -3529,7 +3529,8 @@ flatview_extend_translation(FlatView *fv, hwaddr addr,
 void *address_space_map(AddressSpace *as,
                         hwaddr addr,
                         hwaddr *plen,
-                        bool is_write)
+                        bool is_write,
+                        MemTxAttrs attrs)
 {
     hwaddr len = *plen;
     hwaddr l, xlat;
@@ -3616,7 +3617,8 @@ void *cpu_physical_memory_map(hwaddr addr,
                               hwaddr *plen,
                               int is_write)
 {
-    return address_space_map(&address_space_memory, addr, plen, is_write);
+    return address_space_map(&address_space_memory, addr, plen, is_write,
+                             MEMTXATTRS_UNSPECIFIED);
 }
 
 void cpu_physical_memory_unmap(void *buffer, hwaddr len,
diff --git a/target/ppc/mmu-hash64.c b/target/ppc/mmu-hash64.c
index a1db20e3a8..aa200cba4c 100644
--- a/target/ppc/mmu-hash64.c
+++ b/target/ppc/mmu-hash64.c
@@ -431,7 +431,8 @@ const ppc_hash_pte64_t *ppc_hash64_map_hptes(PowerPCCPU *cpu,
         return NULL;
     }
 
-    hptes = address_space_map(CPU(cpu)->as, base + pte_offset, &plen, false);
+    hptes = address_space_map(CPU(cpu)->as, base + pte_offset, &plen, false,
+                              MEMTXATTRS_UNSPECIFIED);
     if (plen < (n * HASH_PTE_SIZE_64)) {
         hw_error("%s: Unable to map all requested HPTEs\n", __func__);
     }
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [Qemu-devel] [PATCH 05/27] Make address_space_access_valid() take a MemTxAttrs argument
  2018-05-21 14:03 [Qemu-devel] [PATCH 00/27] iommu: support txattrs, support TCG execution, implement TZ MPC Peter Maydell
                   ` (3 preceding siblings ...)
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 04/27] Make address_space_map() " Peter Maydell
@ 2018-05-21 14:03 ` Peter Maydell
  2018-05-22 10:50   ` Alex Bennée
  2018-05-22 16:14   ` Richard Henderson
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 06/27] Make flatview_extend_translation() " Peter Maydell
                   ` (23 subsequent siblings)
  28 siblings, 2 replies; 114+ messages in thread
From: Peter Maydell @ 2018-05-21 14:03 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: patches, Paolo Bonzini, Richard Henderson, Alex Bennée

As part of plumbing MemTxAttrs down to the IOMMU translate method,
add MemTxAttrs as an argument to address_space_access_valid().
Its callers either have an attrs value to hand, or don't care
and can use MEMTXATTRS_UNSPECIFIED.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 include/exec/memory.h      | 4 +++-
 include/sysemu/dma.h       | 3 ++-
 exec.c                     | 3 ++-
 target/s390x/diag.c        | 6 ++++--
 target/s390x/excp_helper.c | 3 ++-
 target/s390x/mmu_helper.c  | 3 ++-
 target/s390x/sigp.c        | 3 ++-
 7 files changed, 17 insertions(+), 8 deletions(-)

diff --git a/include/exec/memory.h b/include/exec/memory.h
index b1bdb376d4..54263bd23b 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -1937,8 +1937,10 @@ static inline MemoryRegion *address_space_translate(AddressSpace *as,
  * @addr: address within that address space
  * @len: length of the area to be checked
  * @is_write: indicates the transfer direction
+ * @attrs: memory attributes
  */
-bool address_space_access_valid(AddressSpace *as, hwaddr addr, int len, bool is_write);
+bool address_space_access_valid(AddressSpace *as, hwaddr addr, int len,
+                                bool is_write, MemTxAttrs attrs);
 
 /* address_space_map: map a physical memory region into a host virtual address
  *
diff --git a/include/sysemu/dma.h b/include/sysemu/dma.h
index 0d73902634..5da3c4e3c5 100644
--- a/include/sysemu/dma.h
+++ b/include/sysemu/dma.h
@@ -77,7 +77,8 @@ static inline bool dma_memory_valid(AddressSpace *as,
                                     DMADirection dir)
 {
     return address_space_access_valid(as, addr, len,
-                                      dir == DMA_DIRECTION_FROM_DEVICE);
+                                      dir == DMA_DIRECTION_FROM_DEVICE,
+                                      MEMTXATTRS_UNSPECIFIED);
 }
 
 static inline int dma_memory_rw_relaxed(AddressSpace *as, dma_addr_t addr,
diff --git a/exec.c b/exec.c
index 1dc81cfe4a..22af4e8cb9 100644
--- a/exec.c
+++ b/exec.c
@@ -3480,7 +3480,8 @@ static bool flatview_access_valid(FlatView *fv, hwaddr addr, int len,
 }
 
 bool address_space_access_valid(AddressSpace *as, hwaddr addr,
-                                int len, bool is_write)
+                                int len, bool is_write,
+                                MemTxAttrs attrs)
 {
     FlatView *fv;
     bool result;
diff --git a/target/s390x/diag.c b/target/s390x/diag.c
index ac2c40f363..d1d3433aa7 100644
--- a/target/s390x/diag.c
+++ b/target/s390x/diag.c
@@ -87,7 +87,8 @@ void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra)
             return;
         }
         if (!address_space_access_valid(&address_space_memory, addr,
-                                        sizeof(IplParameterBlock), false)) {
+                                        sizeof(IplParameterBlock), false,
+                                        MEMTXATTRS_UNSPECIFIED)) {
             s390_program_interrupt(env, PGM_ADDRESSING, ILEN_AUTO, ra);
             return;
         }
@@ -116,7 +117,8 @@ out:
             return;
         }
         if (!address_space_access_valid(&address_space_memory, addr,
-                                        sizeof(IplParameterBlock), true)) {
+                                        sizeof(IplParameterBlock), true,
+                                        MEMTXATTRS_UNSPECIFIED)) {
             s390_program_interrupt(env, PGM_ADDRESSING, ILEN_AUTO, ra);
             return;
         }
diff --git a/target/s390x/excp_helper.c b/target/s390x/excp_helper.c
index dfee221111..f0ce60cff2 100644
--- a/target/s390x/excp_helper.c
+++ b/target/s390x/excp_helper.c
@@ -120,7 +120,8 @@ int s390_cpu_handle_mmu_fault(CPUState *cs, vaddr orig_vaddr, int size,
 
     /* check out of RAM access */
     if (!address_space_access_valid(&address_space_memory, raddr,
-                                    TARGET_PAGE_SIZE, rw)) {
+                                    TARGET_PAGE_SIZE, rw,
+                                    MEMTXATTRS_UNSPECIFIED)) {
         DPRINTF("%s: raddr %" PRIx64 " > ram_size %" PRIx64 "\n", __func__,
                 (uint64_t)raddr, (uint64_t)ram_size);
         trigger_pgm_exception(env, PGM_ADDRESSING, ILEN_AUTO);
diff --git a/target/s390x/mmu_helper.c b/target/s390x/mmu_helper.c
index a25deef5dd..145b62a7ef 100644
--- a/target/s390x/mmu_helper.c
+++ b/target/s390x/mmu_helper.c
@@ -461,7 +461,8 @@ static int translate_pages(S390CPU *cpu, vaddr addr, int nr_pages,
             return ret;
         }
         if (!address_space_access_valid(&address_space_memory, pages[i],
-                                        TARGET_PAGE_SIZE, is_write)) {
+                                        TARGET_PAGE_SIZE, is_write,
+                                        MEMTXATTRS_UNSPECIFIED)) {
             trigger_access_exception(env, PGM_ADDRESSING, ILEN_AUTO, 0);
             return -EFAULT;
         }
diff --git a/target/s390x/sigp.c b/target/s390x/sigp.c
index aff1530c82..c1f9245797 100644
--- a/target/s390x/sigp.c
+++ b/target/s390x/sigp.c
@@ -280,7 +280,8 @@ static void sigp_set_prefix(CPUState *cs, run_on_cpu_data arg)
     cpu_synchronize_state(cs);
 
     if (!address_space_access_valid(&address_space_memory, addr,
-                                    sizeof(struct LowCore), false)) {
+                                    sizeof(struct LowCore), false,
+                                    MEMTXATTRS_UNSPECIFIED)) {
         set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
         return;
     }
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [Qemu-devel] [PATCH 06/27] Make flatview_extend_translation() take a MemTxAttrs argument
  2018-05-21 14:03 [Qemu-devel] [PATCH 00/27] iommu: support txattrs, support TCG execution, implement TZ MPC Peter Maydell
                   ` (4 preceding siblings ...)
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 05/27] Make address_space_access_valid() " Peter Maydell
@ 2018-05-21 14:03 ` Peter Maydell
  2018-05-22 10:56   ` Alex Bennée
  2018-05-22 16:15   ` Richard Henderson
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 07/27] Make memory_region_access_valid() " Peter Maydell
                   ` (22 subsequent siblings)
  28 siblings, 2 replies; 114+ messages in thread
From: Peter Maydell @ 2018-05-21 14:03 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: patches, Paolo Bonzini, Richard Henderson, Alex Bennée

As part of plumbing MemTxAttrs down to the IOMMU translate method,
add MemTxAttrs as an argument to flatview_extend_translation().
Its callers either have an attrs value to hand, or don't care
and can use MEMTXATTRS_UNSPECIFIED.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 exec.c | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/exec.c b/exec.c
index 22af4e8cb9..718b33921b 100644
--- a/exec.c
+++ b/exec.c
@@ -3495,9 +3495,9 @@ bool address_space_access_valid(AddressSpace *as, hwaddr addr,
 
 static hwaddr
 flatview_extend_translation(FlatView *fv, hwaddr addr,
-                                 hwaddr target_len,
-                                 MemoryRegion *mr, hwaddr base, hwaddr len,
-                                 bool is_write)
+                            hwaddr target_len,
+                            MemoryRegion *mr, hwaddr base, hwaddr len,
+                            bool is_write, MemTxAttrs attrs)
 {
     hwaddr done = 0;
     hwaddr xlat;
@@ -3574,7 +3574,7 @@ void *address_space_map(AddressSpace *as,
 
     memory_region_ref(mr);
     *plen = flatview_extend_translation(fv, addr, len, mr, xlat,
-                                             l, is_write);
+                                        l, is_write, attrs);
     ptr = qemu_ram_ptr_length(mr->ram_block, xlat, plen, true);
     rcu_read_unlock();
 
@@ -3659,8 +3659,13 @@ int64_t address_space_cache_init(MemoryRegionCache *cache,
     mr = cache->mrs.mr;
     memory_region_ref(mr);
     if (memory_access_is_direct(mr, is_write)) {
+        /* We don't care about the memory attributes here as we're only
+         * doing this if we found actual RAM, which behaves the same
+         * regardless of attributes; so UNSPECIFIED is fine.
+         */
         l = flatview_extend_translation(cache->fv, addr, len, mr,
-                                        cache->xlat, l, is_write);
+                                        cache->xlat, l, is_write,
+                                        MEMTXATTRS_UNSPECIFIED);
         cache->ptr = qemu_ram_ptr_length(mr->ram_block, cache->xlat, &l, true);
     } else {
         cache->ptr = NULL;
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [Qemu-devel] [PATCH 07/27] Make memory_region_access_valid() take a MemTxAttrs argument
  2018-05-21 14:03 [Qemu-devel] [PATCH 00/27] iommu: support txattrs, support TCG execution, implement TZ MPC Peter Maydell
                   ` (5 preceding siblings ...)
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 06/27] Make flatview_extend_translation() " Peter Maydell
@ 2018-05-21 14:03 ` Peter Maydell
  2018-05-22 10:57   ` Alex Bennée
  2018-05-22 16:17   ` Richard Henderson
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 08/27] Make MemoryRegion valid.accepts callback " Peter Maydell
                   ` (21 subsequent siblings)
  28 siblings, 2 replies; 114+ messages in thread
From: Peter Maydell @ 2018-05-21 14:03 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: patches, Paolo Bonzini, Richard Henderson, Alex Bennée

As part of plumbing MemTxAttrs down to the IOMMU translate method,
add MemTxAttrs as an argument to memory_region_access_valid().
Its callers either have an attrs value to hand, or don't care
and can use MEMTXATTRS_UNSPECIFIED.

The callsite in flatview_access_valid() is part of a recursive
loop flatview_access_valid() -> memory_region_access_valid() ->
 subpage_accepts() -> flatview_access_valid(); we make it pass
MEMTXATTRS_UNSPECIFIED for now, until the next several commits
have plumbed an attrs parameter through the rest of the loop
and we can add an attrs parameter to flatview_access_valid().

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 include/exec/memory-internal.h | 3 ++-
 exec.c                         | 4 +++-
 hw/s390x/s390-pci-inst.c       | 3 ++-
 memory.c                       | 7 ++++---
 4 files changed, 11 insertions(+), 6 deletions(-)

diff --git a/include/exec/memory-internal.h b/include/exec/memory-internal.h
index 58399b9318..56c25c0ef7 100644
--- a/include/exec/memory-internal.h
+++ b/include/exec/memory-internal.h
@@ -37,7 +37,8 @@ void flatview_unref(FlatView *view);
 extern const MemoryRegionOps unassigned_mem_ops;
 
 bool memory_region_access_valid(MemoryRegion *mr, hwaddr addr,
-                                unsigned size, bool is_write);
+                                unsigned size, bool is_write,
+                                MemTxAttrs attrs);
 
 void flatview_add_to_dispatch(FlatView *fv, MemoryRegionSection *section);
 AddressSpaceDispatch *address_space_dispatch_new(FlatView *fv);
diff --git a/exec.c b/exec.c
index 718b33921b..6cf97b5d28 100644
--- a/exec.c
+++ b/exec.c
@@ -3468,7 +3468,9 @@ static bool flatview_access_valid(FlatView *fv, hwaddr addr, int len,
         mr = flatview_translate(fv, addr, &xlat, &l, is_write);
         if (!memory_access_is_direct(mr, is_write)) {
             l = memory_access_size(mr, l, addr);
-            if (!memory_region_access_valid(mr, xlat, l, is_write)) {
+            /* When our callers all have attrs we'll pass them through here */
+            if (!memory_region_access_valid(mr, xlat, l, is_write,
+                                            MEMTXATTRS_UNSPECIFIED)) {
                 return false;
             }
         }
diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c
index 02a815fd31..d1a5f79678 100644
--- a/hw/s390x/s390-pci-inst.c
+++ b/hw/s390x/s390-pci-inst.c
@@ -762,7 +762,8 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr,
     mr = s390_get_subregion(mr, offset, len);
     offset -= mr->addr;
 
-    if (!memory_region_access_valid(mr, offset, len, true)) {
+    if (!memory_region_access_valid(mr, offset, len, true,
+                                    MEMTXATTRS_UNSPECIFIED)) {
         s390_program_interrupt(env, PGM_OPERAND, 6, ra);
         return 0;
     }
diff --git a/memory.c b/memory.c
index fc7f9b782b..279f7c9b4a 100644
--- a/memory.c
+++ b/memory.c
@@ -1347,7 +1347,8 @@ static const MemoryRegionOps ram_device_mem_ops = {
 bool memory_region_access_valid(MemoryRegion *mr,
                                 hwaddr addr,
                                 unsigned size,
-                                bool is_write)
+                                bool is_write,
+                                MemTxAttrs attrs)
 {
     int access_size_min, access_size_max;
     int access_size, i;
@@ -1416,7 +1417,7 @@ MemTxResult memory_region_dispatch_read(MemoryRegion *mr,
 {
     MemTxResult r;
 
-    if (!memory_region_access_valid(mr, addr, size, false)) {
+    if (!memory_region_access_valid(mr, addr, size, false, attrs)) {
         *pval = unassigned_mem_read(mr, addr, size);
         return MEMTX_DECODE_ERROR;
     }
@@ -1458,7 +1459,7 @@ MemTxResult memory_region_dispatch_write(MemoryRegion *mr,
                                          unsigned size,
                                          MemTxAttrs attrs)
 {
-    if (!memory_region_access_valid(mr, addr, size, true)) {
+    if (!memory_region_access_valid(mr, addr, size, true, attrs)) {
         unassigned_mem_write(mr, addr, data, size);
         return MEMTX_DECODE_ERROR;
     }
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [Qemu-devel] [PATCH 08/27] Make MemoryRegion valid.accepts callback take a MemTxAttrs argument
  2018-05-21 14:03 [Qemu-devel] [PATCH 00/27] iommu: support txattrs, support TCG execution, implement TZ MPC Peter Maydell
                   ` (6 preceding siblings ...)
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 07/27] Make memory_region_access_valid() " Peter Maydell
@ 2018-05-21 14:03 ` Peter Maydell
  2018-05-22 10:58   ` Alex Bennée
  2018-05-22 16:20   ` Richard Henderson
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 09/27] Make flatview_access_valid() " Peter Maydell
                   ` (20 subsequent siblings)
  28 siblings, 2 replies; 114+ messages in thread
From: Peter Maydell @ 2018-05-21 14:03 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: patches, Paolo Bonzini, Richard Henderson, Alex Bennée

As part of plumbing MemTxAttrs down to the IOMMU translate method,
add MemTxAttrs as an argument to the MemoryRegion valid.accepts
callback. We'll need this for subpage_accepts().

We could take the approach we used with the read and write
callbacks and add new a new _with_attrs version, but since there
are so few implementations of the accepts hook we just change
them all.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 include/exec/memory.h |  3 ++-
 exec.c                |  9 ++++++---
 hw/hppa/dino.c        |  3 ++-
 hw/nvram/fw_cfg.c     | 12 ++++++++----
 hw/scsi/esp.c         |  3 ++-
 hw/xen/xen_pt_msi.c   |  3 ++-
 memory.c              |  5 +++--
 7 files changed, 25 insertions(+), 13 deletions(-)

diff --git a/include/exec/memory.h b/include/exec/memory.h
index 54263bd23b..444fceac55 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -166,7 +166,8 @@ struct MemoryRegionOps {
          * as a machine check exception).
          */
         bool (*accepts)(void *opaque, hwaddr addr,
-                        unsigned size, bool is_write);
+                        unsigned size, bool is_write,
+                        MemTxAttrs attrs);
     } valid;
     /* Internal implementation constraints: */
     struct {
diff --git a/exec.c b/exec.c
index 6cf97b5d28..b58eb0fedd 100644
--- a/exec.c
+++ b/exec.c
@@ -2539,7 +2539,8 @@ static void notdirty_mem_write(void *opaque, hwaddr ram_addr,
 }
 
 static bool notdirty_mem_accepts(void *opaque, hwaddr addr,
-                                 unsigned size, bool is_write)
+                                 unsigned size, bool is_write,
+                                 MemTxAttrs attrs)
 {
     return is_write;
 }
@@ -2762,7 +2763,8 @@ static MemTxResult subpage_write(void *opaque, hwaddr addr,
 }
 
 static bool subpage_accepts(void *opaque, hwaddr addr,
-                            unsigned len, bool is_write)
+                            unsigned len, bool is_write,
+                            MemTxAttrs attrs)
 {
     subpage_t *subpage = opaque;
 #if defined(DEBUG_SUBPAGE)
@@ -2845,7 +2847,8 @@ static void readonly_mem_write(void *opaque, hwaddr addr,
 }
 
 static bool readonly_mem_accepts(void *opaque, hwaddr addr,
-                                 unsigned size, bool is_write)
+                                 unsigned size, bool is_write,
+                                 MemTxAttrs attrs)
 {
     return is_write;
 }
diff --git a/hw/hppa/dino.c b/hw/hppa/dino.c
index 15aefde09c..77463672a3 100644
--- a/hw/hppa/dino.c
+++ b/hw/hppa/dino.c
@@ -137,7 +137,8 @@ static void gsc_to_pci_forwarding(DinoState *s)
 }
 
 static bool dino_chip_mem_valid(void *opaque, hwaddr addr,
-                                unsigned size, bool is_write)
+                                unsigned size, bool is_write,
+                                MemTxAttrs attrs)
 {
     switch (addr) {
     case DINO_IAR0:
diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
index 2a0739d0e9..b23e7f64a8 100644
--- a/hw/nvram/fw_cfg.c
+++ b/hw/nvram/fw_cfg.c
@@ -420,14 +420,16 @@ static void fw_cfg_dma_mem_write(void *opaque, hwaddr addr,
 }
 
 static bool fw_cfg_dma_mem_valid(void *opaque, hwaddr addr,
-                                  unsigned size, bool is_write)
+                                 unsigned size, bool is_write,
+                                 MemTxAttrs attrs)
 {
     return !is_write || ((size == 4 && (addr == 0 || addr == 4)) ||
                          (size == 8 && addr == 0));
 }
 
 static bool fw_cfg_data_mem_valid(void *opaque, hwaddr addr,
-                                  unsigned size, bool is_write)
+                                  unsigned size, bool is_write,
+                                  MemTxAttrs attrs)
 {
     return addr == 0;
 }
@@ -439,7 +441,8 @@ static void fw_cfg_ctl_mem_write(void *opaque, hwaddr addr,
 }
 
 static bool fw_cfg_ctl_mem_valid(void *opaque, hwaddr addr,
-                                 unsigned size, bool is_write)
+                                 unsigned size, bool is_write,
+                                 MemTxAttrs attrs)
 {
     return is_write && size == 2;
 }
@@ -458,7 +461,8 @@ static void fw_cfg_comb_write(void *opaque, hwaddr addr,
 }
 
 static bool fw_cfg_comb_valid(void *opaque, hwaddr addr,
-                                  unsigned size, bool is_write)
+                              unsigned size, bool is_write,
+                              MemTxAttrs attrs)
 {
     return (size == 1) || (is_write && size == 2);
 }
diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index 64ec285826..9ed9727744 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -564,7 +564,8 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
 }
 
 static bool esp_mem_accepts(void *opaque, hwaddr addr,
-                            unsigned size, bool is_write)
+                            unsigned size, bool is_write,
+                            MemTxAttrs attrs)
 {
     return (size == 1) || (is_write && size == 4);
 }
diff --git a/hw/xen/xen_pt_msi.c b/hw/xen/xen_pt_msi.c
index 6d1e3bdeb4..cc514f9157 100644
--- a/hw/xen/xen_pt_msi.c
+++ b/hw/xen/xen_pt_msi.c
@@ -498,7 +498,8 @@ static uint64_t pci_msix_read(void *opaque, hwaddr addr,
 }
 
 static bool pci_msix_accepts(void *opaque, hwaddr addr,
-                             unsigned size, bool is_write)
+                             unsigned size, bool is_write,
+                             MemTxAttrs attrs)
 {
     return !(addr & (size - 1));
 }
diff --git a/memory.c b/memory.c
index 279f7c9b4a..10fa2ddd31 100644
--- a/memory.c
+++ b/memory.c
@@ -1269,7 +1269,8 @@ static void unassigned_mem_write(void *opaque, hwaddr addr,
 }
 
 static bool unassigned_mem_accepts(void *opaque, hwaddr addr,
-                                   unsigned size, bool is_write)
+                                   unsigned size, bool is_write,
+                                   MemTxAttrs attrs)
 {
     return false;
 }
@@ -1374,7 +1375,7 @@ bool memory_region_access_valid(MemoryRegion *mr,
     access_size = MAX(MIN(size, access_size_max), access_size_min);
     for (i = 0; i < size; i += access_size) {
         if (!mr->ops->valid.accepts(mr->opaque, addr + i, access_size,
-                                    is_write)) {
+                                    is_write, attrs)) {
             return false;
         }
     }
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [Qemu-devel] [PATCH 09/27] Make flatview_access_valid() take a MemTxAttrs argument
  2018-05-21 14:03 [Qemu-devel] [PATCH 00/27] iommu: support txattrs, support TCG execution, implement TZ MPC Peter Maydell
                   ` (7 preceding siblings ...)
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 08/27] Make MemoryRegion valid.accepts callback " Peter Maydell
@ 2018-05-21 14:03 ` Peter Maydell
  2018-05-22 10:58   ` Alex Bennée
  2018-05-22 16:33   ` Richard Henderson
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 10/27] Make flatview_translate() " Peter Maydell
                   ` (19 subsequent siblings)
  28 siblings, 2 replies; 114+ messages in thread
From: Peter Maydell @ 2018-05-21 14:03 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: patches, Paolo Bonzini, Richard Henderson, Alex Bennée

As part of plumbing MemTxAttrs down to the IOMMU translate method,
add MemTxAttrs as an argument to flatview_access_valid().
Its callers now all have an attrs value to hand, so we can
correct our earlier temporary use of MEMTXATTRS_UNSPECIFIED.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 exec.c | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/exec.c b/exec.c
index b58eb0fedd..9229fb4058 100644
--- a/exec.c
+++ b/exec.c
@@ -2697,7 +2697,7 @@ static MemTxResult flatview_read(FlatView *fv, hwaddr addr,
 static MemTxResult flatview_write(FlatView *fv, hwaddr addr, MemTxAttrs attrs,
                                   const uint8_t *buf, int len);
 static bool flatview_access_valid(FlatView *fv, hwaddr addr, int len,
-                                  bool is_write);
+                                  bool is_write, MemTxAttrs attrs);
 
 static MemTxResult subpage_read(void *opaque, hwaddr addr, uint64_t *data,
                                 unsigned len, MemTxAttrs attrs)
@@ -2773,7 +2773,7 @@ static bool subpage_accepts(void *opaque, hwaddr addr,
 #endif
 
     return flatview_access_valid(subpage->fv, addr + subpage->base,
-                                 len, is_write);
+                                 len, is_write, attrs);
 }
 
 static const MemoryRegionOps subpage_ops = {
@@ -3461,7 +3461,7 @@ static void cpu_notify_map_clients(void)
 }
 
 static bool flatview_access_valid(FlatView *fv, hwaddr addr, int len,
-                                  bool is_write)
+                                  bool is_write, MemTxAttrs attrs)
 {
     MemoryRegion *mr;
     hwaddr l, xlat;
@@ -3472,8 +3472,7 @@ static bool flatview_access_valid(FlatView *fv, hwaddr addr, int len,
         if (!memory_access_is_direct(mr, is_write)) {
             l = memory_access_size(mr, l, addr);
             /* When our callers all have attrs we'll pass them through here */
-            if (!memory_region_access_valid(mr, xlat, l, is_write,
-                                            MEMTXATTRS_UNSPECIFIED)) {
+            if (!memory_region_access_valid(mr, xlat, l, is_write, attrs)) {
                 return false;
             }
         }
@@ -3493,7 +3492,7 @@ bool address_space_access_valid(AddressSpace *as, hwaddr addr,
 
     rcu_read_lock();
     fv = address_space_to_flatview(as);
-    result = flatview_access_valid(fv, addr, len, is_write);
+    result = flatview_access_valid(fv, addr, len, is_write, attrs);
     rcu_read_unlock();
     return result;
 }
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [Qemu-devel] [PATCH 10/27] Make flatview_translate() take a MemTxAttrs argument
  2018-05-21 14:03 [Qemu-devel] [PATCH 00/27] iommu: support txattrs, support TCG execution, implement TZ MPC Peter Maydell
                   ` (8 preceding siblings ...)
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 09/27] Make flatview_access_valid() " Peter Maydell
@ 2018-05-21 14:03 ` Peter Maydell
  2018-05-22 10:58   ` Alex Bennée
  2018-05-22 16:33   ` Richard Henderson
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 11/27] Make address_space_get_iotlb_entry() " Peter Maydell
                   ` (18 subsequent siblings)
  28 siblings, 2 replies; 114+ messages in thread
From: Peter Maydell @ 2018-05-21 14:03 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: patches, Paolo Bonzini, Richard Henderson, Alex Bennée

As part of plumbing MemTxAttrs down to the IOMMU translate method,
add MemTxAttrs as an argument to flatview_translate(); all its
callers now have attrs available.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 include/exec/memory.h |  7 ++++---
 exec.c                | 17 +++++++++--------
 2 files changed, 13 insertions(+), 11 deletions(-)

diff --git a/include/exec/memory.h b/include/exec/memory.h
index 444fceac55..3980ab47ed 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -1913,7 +1913,8 @@ IOMMUTLBEntry address_space_get_iotlb_entry(AddressSpace *as, hwaddr addr,
  */
 MemoryRegion *flatview_translate(FlatView *fv,
                                  hwaddr addr, hwaddr *xlat,
-                                 hwaddr *len, bool is_write);
+                                 hwaddr *len, bool is_write,
+                                 MemTxAttrs attrs);
 
 static inline MemoryRegion *address_space_translate(AddressSpace *as,
                                                     hwaddr addr, hwaddr *xlat,
@@ -1921,7 +1922,7 @@ static inline MemoryRegion *address_space_translate(AddressSpace *as,
                                                     MemTxAttrs attrs)
 {
     return flatview_translate(address_space_to_flatview(as),
-                              addr, xlat, len, is_write);
+                              addr, xlat, len, is_write, attrs);
 }
 
 /* address_space_access_valid: check for validity of accessing an address
@@ -2030,7 +2031,7 @@ MemTxResult address_space_read(AddressSpace *as, hwaddr addr,
             rcu_read_lock();
             fv = address_space_to_flatview(as);
             l = len;
-            mr = flatview_translate(fv, addr, &addr1, &l, false);
+            mr = flatview_translate(fv, addr, &addr1, &l, false, attrs);
             if (len == l && memory_access_is_direct(mr, false)) {
                 ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
                 memcpy(buf, ptr, len);
diff --git a/exec.c b/exec.c
index 9229fb4058..b818ba87f4 100644
--- a/exec.c
+++ b/exec.c
@@ -618,7 +618,8 @@ iotlb_fail:
 
 /* Called from RCU critical section */
 MemoryRegion *flatview_translate(FlatView *fv, hwaddr addr, hwaddr *xlat,
-                                 hwaddr *plen, bool is_write)
+                                 hwaddr *plen, bool is_write,
+                                 MemTxAttrs attrs)
 {
     MemoryRegion *mr;
     MemoryRegionSection section;
@@ -3152,7 +3153,7 @@ static MemTxResult flatview_write_continue(FlatView *fv, hwaddr addr,
         }
 
         l = len;
-        mr = flatview_translate(fv, addr, &addr1, &l, true);
+        mr = flatview_translate(fv, addr, &addr1, &l, true, attrs);
     }
 
     return result;
@@ -3168,7 +3169,7 @@ static MemTxResult flatview_write(FlatView *fv, hwaddr addr, MemTxAttrs attrs,
     MemTxResult result = MEMTX_OK;
 
     l = len;
-    mr = flatview_translate(fv, addr, &addr1, &l, true);
+    mr = flatview_translate(fv, addr, &addr1, &l, true, attrs);
     result = flatview_write_continue(fv, addr, attrs, buf, len,
                                      addr1, l, mr);
 
@@ -3239,7 +3240,7 @@ MemTxResult flatview_read_continue(FlatView *fv, hwaddr addr,
         }
 
         l = len;
-        mr = flatview_translate(fv, addr, &addr1, &l, false);
+        mr = flatview_translate(fv, addr, &addr1, &l, false, attrs);
     }
 
     return result;
@@ -3254,7 +3255,7 @@ static MemTxResult flatview_read(FlatView *fv, hwaddr addr,
     MemoryRegion *mr;
 
     l = len;
-    mr = flatview_translate(fv, addr, &addr1, &l, false);
+    mr = flatview_translate(fv, addr, &addr1, &l, false, attrs);
     return flatview_read_continue(fv, addr, attrs, buf, len,
                                   addr1, l, mr);
 }
@@ -3468,7 +3469,7 @@ static bool flatview_access_valid(FlatView *fv, hwaddr addr, int len,
 
     while (len > 0) {
         l = len;
-        mr = flatview_translate(fv, addr, &xlat, &l, is_write);
+        mr = flatview_translate(fv, addr, &xlat, &l, is_write, attrs);
         if (!memory_access_is_direct(mr, is_write)) {
             l = memory_access_size(mr, l, addr);
             /* When our callers all have attrs we'll pass them through here */
@@ -3517,7 +3518,7 @@ flatview_extend_translation(FlatView *fv, hwaddr addr,
 
         len = target_len;
         this_mr = flatview_translate(fv, addr, &xlat,
-                                                   &len, is_write);
+                                     &len, is_write, attrs);
         if (this_mr != mr || xlat != base + done) {
             return done;
         }
@@ -3550,7 +3551,7 @@ void *address_space_map(AddressSpace *as,
     l = len;
     rcu_read_lock();
     fv = address_space_to_flatview(as);
-    mr = flatview_translate(fv, addr, &xlat, &l, is_write);
+    mr = flatview_translate(fv, addr, &xlat, &l, is_write, attrs);
 
     if (!memory_access_is_direct(mr, is_write)) {
         if (atomic_xchg(&bounce.in_use, true)) {
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [Qemu-devel] [PATCH 11/27] Make address_space_get_iotlb_entry() take a MemTxAttrs argument
  2018-05-21 14:03 [Qemu-devel] [PATCH 00/27] iommu: support txattrs, support TCG execution, implement TZ MPC Peter Maydell
                   ` (9 preceding siblings ...)
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 10/27] Make flatview_translate() " Peter Maydell
@ 2018-05-21 14:03 ` Peter Maydell
  2018-05-22 11:00   ` Alex Bennée
  2018-05-22 17:29   ` Richard Henderson
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 12/27] Make flatview_do_translate() " Peter Maydell
                   ` (17 subsequent siblings)
  28 siblings, 2 replies; 114+ messages in thread
From: Peter Maydell @ 2018-05-21 14:03 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: patches, Paolo Bonzini, Richard Henderson, Alex Bennée

As part of plumbing MemTxAttrs down to the IOMMU translate method,
add MemTxAttrs as an argument to address_space_get_iotlb_entry().

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 include/exec/memory.h | 2 +-
 exec.c                | 2 +-
 hw/virtio/vhost.c     | 3 ++-
 3 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/include/exec/memory.h b/include/exec/memory.h
index 3980ab47ed..309fdfb89b 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -1896,7 +1896,7 @@ void address_space_cache_destroy(MemoryRegionCache *cache);
  * entry. Should be called from an RCU critical section.
  */
 IOMMUTLBEntry address_space_get_iotlb_entry(AddressSpace *as, hwaddr addr,
-                                            bool is_write);
+                                            bool is_write, MemTxAttrs attrs);
 
 /* address_space_translate: translate an address range into an address space
  * into a MemoryRegion and an address range into that section.  Should be
diff --git a/exec.c b/exec.c
index b818ba87f4..84f2c21ecb 100644
--- a/exec.c
+++ b/exec.c
@@ -582,7 +582,7 @@ static MemoryRegionSection flatview_do_translate(FlatView *fv,
 
 /* Called from RCU critical section */
 IOMMUTLBEntry address_space_get_iotlb_entry(AddressSpace *as, hwaddr addr,
-                                            bool is_write)
+                                            bool is_write, MemTxAttrs attrs)
 {
     MemoryRegionSection section;
     hwaddr xlat, page_mask;
diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index 9d5850a7d7..48f4fd7cc9 100644
--- a/hw/virtio/vhost.c
+++ b/hw/virtio/vhost.c
@@ -895,7 +895,8 @@ int vhost_device_iotlb_miss(struct vhost_dev *dev, uint64_t iova, int write)
     rcu_read_lock();
 
     iotlb = address_space_get_iotlb_entry(dev->vdev->dma_as,
-                                          iova, write);
+                                          iova, write,
+                                          MEMTXATTRS_UNSPECIFIED);
     if (iotlb.target_as != NULL) {
         ret = vhost_memory_region_lookup(dev, iotlb.translated_addr,
                                          &uaddr, &len);
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [Qemu-devel] [PATCH 12/27] Make flatview_do_translate() take a MemTxAttrs argument
  2018-05-21 14:03 [Qemu-devel] [PATCH 00/27] iommu: support txattrs, support TCG execution, implement TZ MPC Peter Maydell
                   ` (10 preceding siblings ...)
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 11/27] Make address_space_get_iotlb_entry() " Peter Maydell
@ 2018-05-21 14:03 ` Peter Maydell
  2018-05-22 11:00   ` Alex Bennée
  2018-05-22 17:29   ` Richard Henderson
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 13/27] Make address_space_translate_iommu " Peter Maydell
                   ` (16 subsequent siblings)
  28 siblings, 2 replies; 114+ messages in thread
From: Peter Maydell @ 2018-05-21 14:03 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: patches, Paolo Bonzini, Richard Henderson, Alex Bennée

As part of plumbing MemTxAttrs down to the IOMMU translate method,
add MemTxAttrs as an argument to flatview_do_translate().

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 exec.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/exec.c b/exec.c
index 84f2c21ecb..af2b82d154 100644
--- a/exec.c
+++ b/exec.c
@@ -541,6 +541,7 @@ unassigned:
  * @is_write: whether the translation operation is for write
  * @is_mmio: whether this can be MMIO, set true if it can
  * @target_as: the address space targeted by the IOMMU
+ * @attrs: memory transaction attributes
  *
  * This function is called from RCU critical section
  */
@@ -551,7 +552,8 @@ static MemoryRegionSection flatview_do_translate(FlatView *fv,
                                                  hwaddr *page_mask_out,
                                                  bool is_write,
                                                  bool is_mmio,
-                                                 AddressSpace **target_as)
+                                                 AddressSpace **target_as,
+                                                 MemTxAttrs attrs)
 {
     MemoryRegionSection *section;
     IOMMUMemoryRegion *iommu_mr;
@@ -592,7 +594,8 @@ IOMMUTLBEntry address_space_get_iotlb_entry(AddressSpace *as, hwaddr addr,
      * but page mask.
      */
     section = flatview_do_translate(address_space_to_flatview(as), addr, &xlat,
-                                    NULL, &page_mask, is_write, false, &as);
+                                    NULL, &page_mask, is_write, false, &as,
+                                    attrs);
 
     /* Illegal translation */
     if (section.mr == &io_mem_unassigned) {
@@ -627,7 +630,7 @@ MemoryRegion *flatview_translate(FlatView *fv, hwaddr addr, hwaddr *xlat,
 
     /* This can be MMIO, so setup MMIO bit. */
     section = flatview_do_translate(fv, addr, xlat, plen, NULL,
-                                    is_write, true, &as);
+                                    is_write, true, &as, attrs);
     mr = section.mr;
 
     if (xen_enabled() && memory_access_is_direct(mr, is_write)) {
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [Qemu-devel] [PATCH 13/27] Make address_space_translate_iommu take a MemTxAttrs argument
  2018-05-21 14:03 [Qemu-devel] [PATCH 00/27] iommu: support txattrs, support TCG execution, implement TZ MPC Peter Maydell
                   ` (11 preceding siblings ...)
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 12/27] Make flatview_do_translate() " Peter Maydell
@ 2018-05-21 14:03 ` Peter Maydell
  2018-05-22 11:00   ` Alex Bennée
  2018-05-22 17:30   ` Richard Henderson
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 14/27] iommu: Add IOMMU index concept to IOMMU API Peter Maydell
                   ` (15 subsequent siblings)
  28 siblings, 2 replies; 114+ messages in thread
From: Peter Maydell @ 2018-05-21 14:03 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: patches, Paolo Bonzini, Richard Henderson, Alex Bennée

As part of plumbing MemTxAttrs down to the IOMMU translate method,
add MemTxAttrs as an argument to address_space_translate_iommu().

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 exec.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/exec.c b/exec.c
index af2b82d154..c3baadc349 100644
--- a/exec.c
+++ b/exec.c
@@ -478,6 +478,7 @@ address_space_translate_internal(AddressSpaceDispatch *d, hwaddr addr, hwaddr *x
  * @is_write: whether the translation operation is for write
  * @is_mmio: whether this can be MMIO, set true if it can
  * @target_as: the address space targeted by the IOMMU
+ * @attrs: transaction attributes
  *
  * This function is called from RCU critical section.  It is the common
  * part of flatview_do_translate and address_space_translate_cached.
@@ -488,7 +489,8 @@ static MemoryRegionSection address_space_translate_iommu(IOMMUMemoryRegion *iomm
                                                          hwaddr *page_mask_out,
                                                          bool is_write,
                                                          bool is_mmio,
-                                                         AddressSpace **target_as)
+                                                         AddressSpace **target_as,
+                                                         MemTxAttrs attrs)
 {
     MemoryRegionSection *section;
     hwaddr page_mask = (hwaddr)-1;
@@ -572,7 +574,7 @@ static MemoryRegionSection flatview_do_translate(FlatView *fv,
         return address_space_translate_iommu(iommu_mr, xlat,
                                              plen_out, page_mask_out,
                                              is_write, is_mmio,
-                                             target_as);
+                                             target_as, attrs);
     }
     if (page_mask_out) {
         /* Not behind an IOMMU, use default page size. */
@@ -3735,7 +3737,7 @@ static inline MemoryRegion *address_space_translate_cached(
 
     section = address_space_translate_iommu(iommu_mr, xlat, plen,
                                             NULL, is_write, true,
-                                            &target_as);
+                                            &target_as, attrs);
     return section.mr;
 }
 
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [Qemu-devel] [PATCH 14/27] iommu: Add IOMMU index concept to IOMMU API
  2018-05-21 14:03 [Qemu-devel] [PATCH 00/27] iommu: support txattrs, support TCG execution, implement TZ MPC Peter Maydell
                   ` (12 preceding siblings ...)
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 13/27] Make address_space_translate_iommu " Peter Maydell
@ 2018-05-21 14:03 ` Peter Maydell
  2018-05-22  3:03   ` Peter Xu
                     ` (2 more replies)
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 15/27] iommu: Add IOMMU index argument to notifier APIs Peter Maydell
                   ` (14 subsequent siblings)
  28 siblings, 3 replies; 114+ messages in thread
From: Peter Maydell @ 2018-05-21 14:03 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: patches, Paolo Bonzini, Richard Henderson, Alex Bennée

If an IOMMU supports mappings that care about the memory
transaction attributes, then it no longer has a unique
address -> output mapping, but more than one. We can
represent these using an IOMMU index, analogous to TCG's
mmu indexes.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 include/exec/memory.h | 52 +++++++++++++++++++++++++++++++++++++++++++
 memory.c              | 23 +++++++++++++++++++
 2 files changed, 75 insertions(+)

diff --git a/include/exec/memory.h b/include/exec/memory.h
index 309fdfb89b..f6226fb263 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -206,6 +206,20 @@ enum IOMMUMemoryRegionAttr {
  * to report whenever mappings are changed, by calling
  * memory_region_notify_iommu() (or, if necessary, by calling
  * memory_region_notify_one() for each registered notifier).
+ *
+ * Conceptually an IOMMU provides a mapping from input address
+ * to an output TLB entry. If the IOMMU is aware of memory transaction
+ * attributes and the output TLB entry depends on the transaction
+ * attributes, we represent this using IOMMU indexes. Each index
+ * selects a particular translation table that the IOMMU has:
+ *   @attrs_to_index returns the IOMMU index for a set of transaction attributes
+ *   @translate takes an input address and an IOMMU index
+ * and the mapping returned can only depend on the input address and the
+ * IOMMU index.
+ *
+ * Most IOMMUs don't care about the transaction attributes and support
+ * only a single IOMMU index. A more complex IOMMU might have one index
+ * for secure transactions and one for non-secure transactions.
  */
 typedef struct IOMMUMemoryRegionClass {
     /* private */
@@ -290,6 +304,26 @@ typedef struct IOMMUMemoryRegionClass {
      */
     int (*get_attr)(IOMMUMemoryRegion *iommu, enum IOMMUMemoryRegionAttr attr,
                     void *data);
+
+    /* Return the IOMMU index to use for a given set of transaction attributes.
+     *
+     * Optional method: if an IOMMU only supports a single IOMMU index then
+     * the default implementation of memory_region_iommu_attrs_to_index()
+     * will return 0.
+     *
+     * The indexes supported by an IOMMU must be contiguous, starting at 0.
+     *
+     * @iommu: the IOMMUMemoryRegion
+     * @attrs: memory transaction attributes
+     */
+    int (*attrs_to_index)(IOMMUMemoryRegion *iommu, MemTxAttrs attrs);
+
+    /* Return the number of IOMMU indexes this IOMMU supports.
+     *
+     * Optional method: if this method is not provided, then
+     * memory_region_iommu_num_indexes() will return 1, indicating that
+     * only a single IOMMU index is supported.
+     */
 } IOMMUMemoryRegionClass;
 
 typedef struct CoalescedMemoryRange CoalescedMemoryRange;
@@ -1077,6 +1111,24 @@ int memory_region_iommu_get_attr(IOMMUMemoryRegion *iommu_mr,
                                  enum IOMMUMemoryRegionAttr attr,
                                  void *data);
 
+/**
+ * memory_region_iommu_attrs_to_index: return the IOMMU index to
+ * use for translations with the given memory transaction attributes.
+ *
+ * @iommu_mr: the memory region
+ * @attrs: the memory transaction attributes
+ */
+int memory_region_iommu_attrs_to_index(IOMMUMemoryRegion *iommu_mr,
+                                       MemTxAttrs attrs);
+
+/**
+ * memory_region_iommu_num_indexes: return the total number of IOMMU
+ * indexes that this IOMMU supports.
+ *
+ * @iommu_mr: the memory region
+ */
+int memory_region_iommu_num_indexes(IOMMUMemoryRegion *iommu_mr);
+
 /**
  * memory_region_name: get a memory region's name
  *
diff --git a/memory.c b/memory.c
index 10fa2ddd31..07d5fa7862 100644
--- a/memory.c
+++ b/memory.c
@@ -1918,6 +1918,29 @@ int memory_region_iommu_get_attr(IOMMUMemoryRegion *iommu_mr,
     return imrc->get_attr(iommu_mr, attr, data);
 }
 
+int memory_region_iommu_attrs_to_index(IOMMUMemoryRegion *iommu_mr,
+                                       MemTxAttrs attrs)
+{
+    IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_GET_CLASS(iommu_mr);
+
+    if (!imrc->attrs_to_index) {
+        return 0;
+    }
+
+    return imrc->attrs_to_index(iommu_mr, attrs);
+}
+
+int memory_region_iommu_num_indexes(IOMMUMemoryRegion *iommu_mr)
+{
+    IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_GET_CLASS(iommu_mr);
+
+    if (!imrc->num_indexes) {
+        return 1;
+    }
+
+    return imrc->num_indexes(iommu_mr);
+}
+
 void memory_region_set_log(MemoryRegion *mr, bool log, unsigned client)
 {
     uint8_t mask = 1 << client;
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [Qemu-devel] [PATCH 15/27] iommu: Add IOMMU index argument to notifier APIs
  2018-05-21 14:03 [Qemu-devel] [PATCH 00/27] iommu: support txattrs, support TCG execution, implement TZ MPC Peter Maydell
                   ` (13 preceding siblings ...)
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 14/27] iommu: Add IOMMU index concept to IOMMU API Peter Maydell
@ 2018-05-21 14:03 ` Peter Maydell
  2018-05-22 17:45   ` Richard Henderson
                     ` (2 more replies)
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 16/27] iommu: Add IOMMU index argument to translate method Peter Maydell
                   ` (13 subsequent siblings)
  28 siblings, 3 replies; 114+ messages in thread
From: Peter Maydell @ 2018-05-21 14:03 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: patches, Paolo Bonzini, Richard Henderson, Alex Bennée

Add support for multiple IOMMU indexes to the IOMMU notifier APIs.
When initializing a notifier with iommu_notifier_init(), the caller
must pass the IOMMU index that it is interested in. When a change
happens, the IOMMU implementation must pass
memory_region_notify_iommu() the IOMMU index that has changed and
that notifiers must be called for.

IOMMUs which support only a single index don't need to change.
Callers which only really support working with IOMMUs with a single
index can use the result of passing MEMTXATTRS_UNSPECIFIED to
memory_region_iommu_attrs_to_index().

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 include/exec/memory.h    | 11 ++++++++++-
 hw/i386/intel_iommu.c    |  4 ++--
 hw/ppc/spapr_iommu.c     |  2 +-
 hw/s390x/s390-pci-inst.c |  4 ++--
 hw/vfio/common.c         |  6 +++++-
 hw/virtio/vhost.c        |  7 ++++++-
 memory.c                 |  8 +++++++-
 7 files changed, 33 insertions(+), 9 deletions(-)

diff --git a/include/exec/memory.h b/include/exec/memory.h
index f6226fb263..4e6b125add 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -71,6 +71,7 @@ struct IOMMUTLBEntry {
     hwaddr           iova;
     hwaddr           translated_addr;
     hwaddr           addr_mask;  /* 0xfff = 4k translation */
+    int              iommu_idx;
     IOMMUAccessFlags perm;
 };
 
@@ -98,18 +99,21 @@ struct IOMMUNotifier {
     /* Notify for address space range start <= addr <= end */
     hwaddr start;
     hwaddr end;
+    int iommu_idx;
     QLIST_ENTRY(IOMMUNotifier) node;
 };
 typedef struct IOMMUNotifier IOMMUNotifier;
 
 static inline void iommu_notifier_init(IOMMUNotifier *n, IOMMUNotify fn,
                                        IOMMUNotifierFlag flags,
-                                       hwaddr start, hwaddr end)
+                                       hwaddr start, hwaddr end,
+                                       int iommu_idx)
 {
     n->notify = fn;
     n->notifier_flags = flags;
     n->start = start;
     n->end = end;
+    n->iommu_idx = iommu_idx;
 }
 
 /*
@@ -323,7 +327,10 @@ typedef struct IOMMUMemoryRegionClass {
      * Optional method: if this method is not provided, then
      * memory_region_iommu_num_indexes() will return 1, indicating that
      * only a single IOMMU index is supported.
+     *
+     * @iommu: the IOMMUMemoryRegion
      */
+    int (*num_indexes)(IOMMUMemoryRegion *iommu);
 } IOMMUMemoryRegionClass;
 
 typedef struct CoalescedMemoryRange CoalescedMemoryRange;
@@ -1028,11 +1035,13 @@ uint64_t memory_region_iommu_get_min_page_size(IOMMUMemoryRegion *iommu_mr);
  * should be notified with an UNMAP followed by a MAP.
  *
  * @iommu_mr: the memory region that was changed
+ * @iommu_idx: the IOMMU index for the translation table which has changed
  * @entry: the new entry in the IOMMU translation table.  The entry
  *         replaces all old entries for the same virtual I/O address range.
  *         Deleted entries have .@perm == 0.
  */
 void memory_region_notify_iommu(IOMMUMemoryRegion *iommu_mr,
+                                int iommu_idx,
                                 IOMMUTLBEntry entry);
 
 /**
diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c
index fb31de9416..b8c9354b0b 100644
--- a/hw/i386/intel_iommu.c
+++ b/hw/i386/intel_iommu.c
@@ -1376,7 +1376,7 @@ static void vtd_iotlb_domain_invalidate(IntelIOMMUState *s, uint16_t domain_id)
 static int vtd_page_invalidate_notify_hook(IOMMUTLBEntry *entry,
                                            void *private)
 {
-    memory_region_notify_iommu((IOMMUMemoryRegion *)private, *entry);
+    memory_region_notify_iommu((IOMMUMemoryRegion *)private, 0, *entry);
     return 0;
 }
 
@@ -1826,7 +1826,7 @@ static bool vtd_process_device_iotlb_desc(IntelIOMMUState *s,
     entry.iova = addr;
     entry.perm = IOMMU_NONE;
     entry.translated_addr = 0;
-    memory_region_notify_iommu(&vtd_dev_as->iommu, entry);
+    memory_region_notify_iommu(&vtd_dev_as->iommu, 0, entry);
 
 done:
     return true;
diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c
index aaa6010d5c..301708e45e 100644
--- a/hw/ppc/spapr_iommu.c
+++ b/hw/ppc/spapr_iommu.c
@@ -428,7 +428,7 @@ static target_ulong put_tce_emu(sPAPRTCETable *tcet, target_ulong ioba,
     entry.translated_addr = tce & page_mask;
     entry.addr_mask = ~page_mask;
     entry.perm = spapr_tce_iommu_access_flags(tce);
-    memory_region_notify_iommu(&tcet->iommu, entry);
+    memory_region_notify_iommu(&tcet->iommu, 0, entry);
 
     return H_SUCCESS;
 }
diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c
index d1a5f79678..7b61367ee3 100644
--- a/hw/s390x/s390-pci-inst.c
+++ b/hw/s390x/s390-pci-inst.c
@@ -589,7 +589,7 @@ static void s390_pci_update_iotlb(S390PCIIOMMU *iommu, S390IOTLBEntry *entry)
             }
 
             notify.perm = IOMMU_NONE;
-            memory_region_notify_iommu(&iommu->iommu_mr, notify);
+            memory_region_notify_iommu(&iommu->iommu_mr, 0, notify);
             notify.perm = entry->perm;
         }
 
@@ -601,7 +601,7 @@ static void s390_pci_update_iotlb(S390PCIIOMMU *iommu, S390IOTLBEntry *entry)
         g_hash_table_replace(iommu->iotlb, &cache->iova, cache);
     }
 
-    memory_region_notify_iommu(&iommu->iommu_mr, notify);
+    memory_region_notify_iommu(&iommu->iommu_mr, 0, notify);
 }
 
 int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra)
diff --git a/hw/vfio/common.c b/hw/vfio/common.c
index 8e57265edf..fb396cf00a 100644
--- a/hw/vfio/common.c
+++ b/hw/vfio/common.c
@@ -507,6 +507,7 @@ static void vfio_listener_region_add(MemoryListener *listener,
     if (memory_region_is_iommu(section->mr)) {
         VFIOGuestIOMMU *giommu;
         IOMMUMemoryRegion *iommu_mr = IOMMU_MEMORY_REGION(section->mr);
+        int iommu_idx;
 
         trace_vfio_listener_region_add_iommu(iova, end);
         /*
@@ -523,10 +524,13 @@ static void vfio_listener_region_add(MemoryListener *listener,
         llend = int128_add(int128_make64(section->offset_within_region),
                            section->size);
         llend = int128_sub(llend, int128_one());
+        iommu_idx = memory_region_iommu_attrs_to_index(iommu_mr,
+                                                       MEMTXATTRS_UNSPECIFIED);
         iommu_notifier_init(&giommu->n, vfio_iommu_map_notify,
                             IOMMU_NOTIFIER_ALL,
                             section->offset_within_region,
-                            int128_get64(llend));
+                            int128_get64(llend),
+                            iommu_idx);
         QLIST_INSERT_HEAD(&container->giommu_list, giommu, giommu_next);
 
         memory_region_register_iommu_notifier(section->mr, &giommu->n);
diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index 48f4fd7cc9..6218df7683 100644
--- a/hw/virtio/vhost.c
+++ b/hw/virtio/vhost.c
@@ -657,6 +657,8 @@ static void vhost_iommu_region_add(MemoryListener *listener,
                                          iommu_listener);
     struct vhost_iommu *iommu;
     Int128 end;
+    int iommu_idx;
+    IOMMUMemoryRegion *iommu_mr = IOMMU_MEMORY_REGION(section->mr);
 
     if (!memory_region_is_iommu(section->mr)) {
         return;
@@ -666,10 +668,13 @@ static void vhost_iommu_region_add(MemoryListener *listener,
     end = int128_add(int128_make64(section->offset_within_region),
                      section->size);
     end = int128_sub(end, int128_one());
+    iommu_idx = memory_region_iommu_attrs_to_index(iommu_mr,
+                                                   MEMTXATTRS_UNSPECIFIED);
     iommu_notifier_init(&iommu->n, vhost_iommu_unmap_notify,
                         IOMMU_NOTIFIER_UNMAP,
                         section->offset_within_region,
-                        int128_get64(end));
+                        int128_get64(end),
+                        iommu_idx);
     iommu->mr = section->mr;
     iommu->iommu_offset = section->offset_within_address_space -
                           section->offset_within_region;
diff --git a/memory.c b/memory.c
index 07d5fa7862..accb28d694 100644
--- a/memory.c
+++ b/memory.c
@@ -1802,6 +1802,9 @@ void memory_region_register_iommu_notifier(MemoryRegion *mr,
     iommu_mr = IOMMU_MEMORY_REGION(mr);
     assert(n->notifier_flags != IOMMU_NOTIFIER_NONE);
     assert(n->start <= n->end);
+    assert(n->iommu_idx >= 0 &&
+           n->iommu_idx < memory_region_iommu_num_indexes(iommu_mr));
+
     QLIST_INSERT_HEAD(&iommu_mr->iommu_notify, n, node);
     memory_region_update_iommu_notify_flags(iommu_mr);
 }
@@ -1894,6 +1897,7 @@ void memory_region_notify_one(IOMMUNotifier *notifier,
 }
 
 void memory_region_notify_iommu(IOMMUMemoryRegion *iommu_mr,
+                                int iommu_idx,
                                 IOMMUTLBEntry entry)
 {
     IOMMUNotifier *iommu_notifier;
@@ -1901,7 +1905,9 @@ void memory_region_notify_iommu(IOMMUMemoryRegion *iommu_mr,
     assert(memory_region_is_iommu(MEMORY_REGION(iommu_mr)));
 
     IOMMU_NOTIFIER_FOREACH(iommu_notifier, iommu_mr) {
-        memory_region_notify_one(iommu_notifier, &entry);
+        if (iommu_notifier->iommu_idx == iommu_idx) {
+            memory_region_notify_one(iommu_notifier, &entry);
+        }
     }
 }
 
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [Qemu-devel] [PATCH 16/27] iommu: Add IOMMU index argument to translate method
  2018-05-21 14:03 [Qemu-devel] [PATCH 00/27] iommu: support txattrs, support TCG execution, implement TZ MPC Peter Maydell
                   ` (14 preceding siblings ...)
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 15/27] iommu: Add IOMMU index argument to notifier APIs Peter Maydell
@ 2018-05-21 14:03 ` Peter Maydell
  2018-05-22 18:06   ` Richard Henderson
  2018-05-23  9:11   ` Alex Bennée
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 17/27] exec.c: Handle IOMMUs in address_space_translate_for_iotlb() Peter Maydell
                   ` (12 subsequent siblings)
  28 siblings, 2 replies; 114+ messages in thread
From: Peter Maydell @ 2018-05-21 14:03 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: patches, Paolo Bonzini, Richard Henderson, Alex Bennée

Add an IOMMU index argument to the translate method of
IOMMUs. Since all of our current IOMMU implementations
support only a single IOMMU index, this has no effect
on the behaviour.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 include/exec/memory.h    |  3 ++-
 exec.c                   | 11 +++++++++--
 hw/alpha/typhoon.c       |  3 ++-
 hw/arm/smmuv3.c          |  2 +-
 hw/dma/rc4030.c          |  2 +-
 hw/i386/amd_iommu.c      |  2 +-
 hw/i386/intel_iommu.c    |  2 +-
 hw/ppc/spapr_iommu.c     |  3 ++-
 hw/s390x/s390-pci-bus.c  |  2 +-
 hw/sparc/sun4m_iommu.c   |  3 ++-
 hw/sparc64/sun4u_iommu.c |  2 +-
 memory.c                 |  2 +-
 12 files changed, 24 insertions(+), 13 deletions(-)

diff --git a/include/exec/memory.h b/include/exec/memory.h
index 4e6b125add..b25cf527bb 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -252,9 +252,10 @@ typedef struct IOMMUMemoryRegionClass {
      * @iommu: the IOMMUMemoryRegion
      * @hwaddr: address to be translated within the memory region
      * @flag: requested access permissions
+     * @iommu_idx: IOMMU index for the translation
      */
     IOMMUTLBEntry (*translate)(IOMMUMemoryRegion *iommu, hwaddr addr,
-                               IOMMUAccessFlags flag);
+                               IOMMUAccessFlags flag, int iommu_idx);
     /* Returns minimum supported page size in bytes.
      * If this method is not provided then the minimum is assumed to
      * be TARGET_PAGE_SIZE.
diff --git a/exec.c b/exec.c
index c3baadc349..c9285c9c39 100644
--- a/exec.c
+++ b/exec.c
@@ -498,8 +498,15 @@ static MemoryRegionSection address_space_translate_iommu(IOMMUMemoryRegion *iomm
     do {
         hwaddr addr = *xlat;
         IOMMUMemoryRegionClass *imrc = memory_region_get_iommu_class_nocheck(iommu_mr);
-        IOMMUTLBEntry iotlb = imrc->translate(iommu_mr, addr, is_write ?
-                                              IOMMU_WO : IOMMU_RO);
+        int iommu_idx = 0;
+        IOMMUTLBEntry iotlb;
+
+        if (imrc->attrs_to_index) {
+            iommu_idx = imrc->attrs_to_index(iommu_mr, attrs);
+        }
+
+        iotlb = imrc->translate(iommu_mr, addr, is_write ?
+                                IOMMU_WO : IOMMU_RO, iommu_idx);
 
         if (!(iotlb.perm & (1 << is_write))) {
             goto unassigned;
diff --git a/hw/alpha/typhoon.c b/hw/alpha/typhoon.c
index 6a40869488..d3ed7cdbe8 100644
--- a/hw/alpha/typhoon.c
+++ b/hw/alpha/typhoon.c
@@ -666,7 +666,8 @@ static bool window_translate(TyphoonWindow *win, hwaddr addr,
    Pchip and generate a machine check interrupt.  */
 static IOMMUTLBEntry typhoon_translate_iommu(IOMMUMemoryRegion *iommu,
                                              hwaddr addr,
-                                             IOMMUAccessFlags flag)
+                                             IOMMUAccessFlags flag,
+                                             int iommu_idx)
 {
     TyphoonPchip *pchip = container_of(iommu, TyphoonPchip, iommu);
     IOMMUTLBEntry ret;
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index 42dc521c13..978330900d 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -538,7 +538,7 @@ static int smmuv3_decode_config(IOMMUMemoryRegion *mr, SMMUTransCfg *cfg,
 }
 
 static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
-                                      IOMMUAccessFlags flag)
+                                      IOMMUAccessFlags flag, int iommu_idx)
 {
     SMMUDevice *sdev = container_of(mr, SMMUDevice, iommu);
     SMMUv3State *s = sdev->smmu;
diff --git a/hw/dma/rc4030.c b/hw/dma/rc4030.c
index 5d4833eeca..ccd8612888 100644
--- a/hw/dma/rc4030.c
+++ b/hw/dma/rc4030.c
@@ -491,7 +491,7 @@ static const MemoryRegionOps jazzio_ops = {
 };
 
 static IOMMUTLBEntry rc4030_dma_translate(IOMMUMemoryRegion *iommu, hwaddr addr,
-                                          IOMMUAccessFlags flag)
+                                          IOMMUAccessFlags flag, int iommu_idx)
 {
     rc4030State *s = container_of(iommu, rc4030State, dma_mr);
     IOMMUTLBEntry ret = {
diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c
index 63d46ff6ee..1fd669fef8 100644
--- a/hw/i386/amd_iommu.c
+++ b/hw/i386/amd_iommu.c
@@ -991,7 +991,7 @@ static inline bool amdvi_is_interrupt_addr(hwaddr addr)
 }
 
 static IOMMUTLBEntry amdvi_translate(IOMMUMemoryRegion *iommu, hwaddr addr,
-                                     IOMMUAccessFlags flag)
+                                     IOMMUAccessFlags flag, int iommu_idx)
 {
     AMDVIAddressSpace *as = container_of(iommu, AMDVIAddressSpace, iommu);
     AMDVIState *s = as->iommu_state;
diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c
index b8c9354b0b..a4b9a254bd 100644
--- a/hw/i386/intel_iommu.c
+++ b/hw/i386/intel_iommu.c
@@ -2282,7 +2282,7 @@ static void vtd_mem_write(void *opaque, hwaddr addr,
 }
 
 static IOMMUTLBEntry vtd_iommu_translate(IOMMUMemoryRegion *iommu, hwaddr addr,
-                                         IOMMUAccessFlags flag)
+                                         IOMMUAccessFlags flag, int iommu_idx)
 {
     VTDAddressSpace *vtd_as = container_of(iommu, VTDAddressSpace, iommu);
     IntelIOMMUState *s = vtd_as->iommu_state;
diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c
index 301708e45e..1b0880ac9e 100644
--- a/hw/ppc/spapr_iommu.c
+++ b/hw/ppc/spapr_iommu.c
@@ -112,7 +112,8 @@ static void spapr_tce_free_table(uint64_t *table, int fd, uint32_t nb_table)
 /* Called from RCU critical section */
 static IOMMUTLBEntry spapr_tce_translate_iommu(IOMMUMemoryRegion *iommu,
                                                hwaddr addr,
-                                               IOMMUAccessFlags flag)
+                                               IOMMUAccessFlags flag,
+                                               int iommu_idx)
 {
     sPAPRTCETable *tcet = container_of(iommu, sPAPRTCETable, iommu);
     uint64_t tce;
diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c
index 10da87458e..e3e0ebb7f6 100644
--- a/hw/s390x/s390-pci-bus.c
+++ b/hw/s390x/s390-pci-bus.c
@@ -484,7 +484,7 @@ uint16_t s390_guest_io_table_walk(uint64_t g_iota, hwaddr addr,
 }
 
 static IOMMUTLBEntry s390_translate_iommu(IOMMUMemoryRegion *mr, hwaddr addr,
-                                          IOMMUAccessFlags flag)
+                                          IOMMUAccessFlags flag, int iommu_idx)
 {
     S390PCIIOMMU *iommu = container_of(mr, S390PCIIOMMU, iommu_mr);
     S390IOTLBEntry *entry;
diff --git a/hw/sparc/sun4m_iommu.c b/hw/sparc/sun4m_iommu.c
index b677601fc6..7ca1e3fce4 100644
--- a/hw/sparc/sun4m_iommu.c
+++ b/hw/sparc/sun4m_iommu.c
@@ -282,7 +282,8 @@ static void iommu_bad_addr(IOMMUState *s, hwaddr addr,
 /* Called from RCU critical section */
 static IOMMUTLBEntry sun4m_translate_iommu(IOMMUMemoryRegion *iommu,
                                            hwaddr addr,
-                                           IOMMUAccessFlags flags)
+                                           IOMMUAccessFlags flags,
+                                           int iommu_idx)
 {
     IOMMUState *is = container_of(iommu, IOMMUState, iommu);
     hwaddr page, pa;
diff --git a/hw/sparc64/sun4u_iommu.c b/hw/sparc64/sun4u_iommu.c
index eb3aaa87e6..1ef7645ba5 100644
--- a/hw/sparc64/sun4u_iommu.c
+++ b/hw/sparc64/sun4u_iommu.c
@@ -73,7 +73,7 @@
 /* Called from RCU critical section */
 static IOMMUTLBEntry sun4u_translate_iommu(IOMMUMemoryRegion *iommu,
                                            hwaddr addr,
-                                           IOMMUAccessFlags flag)
+                                           IOMMUAccessFlags flag, int iommu_idx)
 {
     IOMMUState *is = container_of(iommu, IOMMUState, iommu);
     hwaddr baseaddr, offset;
diff --git a/memory.c b/memory.c
index accb28d694..ff6cbf5831 100644
--- a/memory.c
+++ b/memory.c
@@ -1835,7 +1835,7 @@ void memory_region_iommu_replay(IOMMUMemoryRegion *iommu_mr, IOMMUNotifier *n)
     granularity = memory_region_iommu_get_min_page_size(iommu_mr);
 
     for (addr = 0; addr < memory_region_size(mr); addr += granularity) {
-        iotlb = imrc->translate(iommu_mr, addr, IOMMU_NONE);
+        iotlb = imrc->translate(iommu_mr, addr, IOMMU_NONE, n->iommu_idx);
         if (iotlb.perm != IOMMU_NONE) {
             n->notify(n, &iotlb);
         }
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [Qemu-devel] [PATCH 17/27] exec.c: Handle IOMMUs in address_space_translate_for_iotlb()
  2018-05-21 14:03 [Qemu-devel] [PATCH 00/27] iommu: support txattrs, support TCG execution, implement TZ MPC Peter Maydell
                   ` (15 preceding siblings ...)
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 16/27] iommu: Add IOMMU index argument to translate method Peter Maydell
@ 2018-05-21 14:03 ` Peter Maydell
  2018-05-23  9:51   ` Alex Bennée
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 18/27] hw/misc/tz-mpc.c: Implement the Arm TrustZone Memory Protection Controller Peter Maydell
                   ` (11 subsequent siblings)
  28 siblings, 1 reply; 114+ messages in thread
From: Peter Maydell @ 2018-05-21 14:03 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: patches, Paolo Bonzini, Richard Henderson, Alex Bennée

Currently we don't support board configurations that put an IOMMU
in the path of the CPU's memory transactions, and instead just
assert() if the memory region fonud in address_space_translate_for_iotlb()
is an IOMMUMemoryRegion.

Remove this limitation by having the function handle IOMMUs.
This is mostly straightforward, but we must make sure we have
a notifier registered for every IOMMU that a transaction has
passed through, so that we can flush the TLB appropriately
when any of the IOMMUs change their mappings.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 include/exec/exec-all.h |   3 +-
 include/qom/cpu.h       |   3 +
 accel/tcg/cputlb.c      |   3 +-
 exec.c                  | 147 +++++++++++++++++++++++++++++++++++++++-
 4 files changed, 152 insertions(+), 4 deletions(-)

diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
index 4d09eaba72..e0ff19b711 100644
--- a/include/exec/exec-all.h
+++ b/include/exec/exec-all.h
@@ -469,7 +469,8 @@ void tb_flush_jmp_cache(CPUState *cpu, target_ulong addr);
 
 MemoryRegionSection *
 address_space_translate_for_iotlb(CPUState *cpu, int asidx, hwaddr addr,
-                                  hwaddr *xlat, hwaddr *plen);
+                                  hwaddr *xlat, hwaddr *plen,
+                                  MemTxAttrs attrs, int *prot);
 hwaddr memory_region_section_get_iotlb(CPUState *cpu,
                                        MemoryRegionSection *section,
                                        target_ulong vaddr,
diff --git a/include/qom/cpu.h b/include/qom/cpu.h
index 9d3afc6c75..d4a30149dd 100644
--- a/include/qom/cpu.h
+++ b/include/qom/cpu.h
@@ -429,6 +429,9 @@ struct CPUState {
     uint16_t pending_tlb_flush;
 
     int hvf_fd;
+
+    /* track IOMMUs whose translations we've cached in the TCG TLB */
+    GSList *iommu_notifiers;
 };
 
 QTAILQ_HEAD(CPUTailQ, CPUState);
diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c
index 05439039e9..c8acaf21e9 100644
--- a/accel/tcg/cputlb.c
+++ b/accel/tcg/cputlb.c
@@ -632,7 +632,8 @@ void tlb_set_page_with_attrs(CPUState *cpu, target_ulong vaddr,
     }
 
     sz = size;
-    section = address_space_translate_for_iotlb(cpu, asidx, paddr, &xlat, &sz);
+    section = address_space_translate_for_iotlb(cpu, asidx, paddr, &xlat, &sz,
+                                                attrs, &prot);
     assert(sz >= TARGET_PAGE_SIZE);
 
     tlb_debug("vaddr=" TARGET_FMT_lx " paddr=0x" TARGET_FMT_plx
diff --git a/exec.c b/exec.c
index c9285c9c39..6c8f2dcc3f 100644
--- a/exec.c
+++ b/exec.c
@@ -650,18 +650,158 @@ MemoryRegion *flatview_translate(FlatView *fv, hwaddr addr, hwaddr *xlat,
     return mr;
 }
 
+typedef struct TCGIOMMUNotifier {
+    IOMMUNotifier n;
+    MemoryRegion *mr;
+    CPUState *cpu;
+    int iommu_idx;
+    bool active;
+} TCGIOMMUNotifier;
+
+static void tcg_iommu_unmap_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb)
+{
+    TCGIOMMUNotifier *notifier = container_of(n, TCGIOMMUNotifier, n);
+
+    if (!notifier->active) {
+        return;
+    }
+    tlb_flush(notifier->cpu);
+    notifier->active = false;
+    /* We leave the notifier struct on the list to avoid reallocating it later.
+     * Generally the number of IOMMUs a CPU deals with will be small.
+     * In any case we can't unregister the iommu notifier from a notify
+     * callback.
+     */
+}
+
+static gint tcg_iommu_find_notifier(gconstpointer a, gconstpointer b)
+{
+    TCGIOMMUNotifier *notifier = (TCGIOMMUNotifier *)a;
+    TCGIOMMUNotifier *seeking = (TCGIOMMUNotifier *)b;
+
+    if (notifier->mr == seeking->mr &&
+        notifier->iommu_idx == seeking->iommu_idx) {
+        return 0;
+    }
+    return 1;
+}
+
+static void tcg_register_iommu_notifier(CPUState *cpu,
+                                        IOMMUMemoryRegion *iommu_mr,
+                                        int iommu_idx)
+{
+    /* Make sure this CPU has an IOMMU notifier registered for this
+     * IOMMU/IOMMU index combination, so that we can flush its TLB
+     * when the IOMMU tells us the mappings we've cached have changed.
+     */
+    TCGIOMMUNotifier seeking = {
+        .mr = MEMORY_REGION(iommu_mr),
+        .iommu_idx = iommu_idx,
+    };
+    TCGIOMMUNotifier *notifier;
+    GSList *found = g_slist_find_custom(cpu->iommu_notifiers,
+                                        &seeking,
+                                        tcg_iommu_find_notifier);
+    if (found) {
+        notifier = found->data;
+    } else {
+        notifier = g_new0(TCGIOMMUNotifier, 1);
+        notifier->mr = seeking.mr;
+        notifier->iommu_idx = iommu_idx;
+        notifier->cpu = cpu;
+        /* Rather than trying to register interest in the specific part
+         * of the iommu's address space that we've accessed and then
+         * expand it later as subsequent accesses touch more of it, we
+         * just register interest in the whole thing, on the assumption
+         * that iommu reconfiguration will be rare.
+         */
+        iommu_notifier_init(&notifier->n,
+                            tcg_iommu_unmap_notify,
+                            IOMMU_NOTIFIER_UNMAP,
+                            0,
+                            HWADDR_MAX,
+                            iommu_idx);
+        memory_region_register_iommu_notifier(notifier->mr, &notifier->n);
+        cpu->iommu_notifiers = g_slist_prepend(cpu->iommu_notifiers,
+                                               notifier);
+    }
+    if (!notifier->active) {
+        notifier->active = true;
+    }
+}
+
+static void tcg_iommu_notifier_destroy(gpointer data)
+{
+    TCGIOMMUNotifier *notifier = data;
+
+    if (notifier->active) {
+        memory_region_unregister_iommu_notifier(notifier->mr, &notifier->n);
+    }
+    g_free(notifier);
+}
+
+static void tcg_iommu_free_notifier_list(CPUState *cpu)
+{
+    /* Destroy the CPU's notifier list */
+    g_slist_free_full(cpu->iommu_notifiers, tcg_iommu_notifier_destroy);
+    cpu->iommu_notifiers = NULL;
+}
+
 /* Called from RCU critical section */
 MemoryRegionSection *
 address_space_translate_for_iotlb(CPUState *cpu, int asidx, hwaddr addr,
-                                  hwaddr *xlat, hwaddr *plen)
+                                  hwaddr *xlat, hwaddr *plen,
+                                  MemTxAttrs attrs, int *prot)
 {
     MemoryRegionSection *section;
+    IOMMUMemoryRegion *iommu_mr;
+    IOMMUMemoryRegionClass *imrc;
+    IOMMUTLBEntry iotlb;
+    int iommu_idx;
     AddressSpaceDispatch *d = atomic_rcu_read(&cpu->cpu_ases[asidx].memory_dispatch);
 
-    section = address_space_translate_internal(d, addr, xlat, plen, false);
+    for (;;) {
+        section = address_space_translate_internal(d, addr, &addr, plen, false);
+
+        iommu_mr = memory_region_get_iommu(section->mr);
+        if (!iommu_mr) {
+            break;
+        }
+
+        imrc = memory_region_get_iommu_class_nocheck(iommu_mr);
+
+        iommu_idx = imrc->attrs_to_index(iommu_mr, attrs);
+        tcg_register_iommu_notifier(cpu, iommu_mr, iommu_idx);
+        /* We need all the permissions, so pass IOMMU_NONE so the IOMMU
+         * doesn't short-cut its translation table walk.
+         */
+        iotlb = imrc->translate(iommu_mr, addr, IOMMU_NONE, iommu_idx);
+        addr = ((iotlb.translated_addr & ~iotlb.addr_mask)
+                | (addr & iotlb.addr_mask));
+        /* Update the caller's prot bits to remove permissions the IOMMU
+         * is giving us a failure response for. If we get down to no
+         * permissions left at all we can give up now.
+         */
+        if (!(iotlb.perm & IOMMU_RO)) {
+            *prot &= ~(PAGE_READ | PAGE_EXEC);
+        }
+        if (!(iotlb.perm & IOMMU_WO)) {
+            *prot &= ~PAGE_WRITE;
+        }
+
+        if (!*prot) {
+            goto translate_fail;
+        }
+
+        d = flatview_to_dispatch(address_space_to_flatview(iotlb.target_as));
+    }
 
     assert(!memory_region_is_iommu(section->mr));
+    *xlat = addr;
     return section;
+
+translate_fail:
+    return &d->map.sections[PHYS_SECTION_UNASSIGNED];
 }
 #endif
 
@@ -820,6 +960,9 @@ void cpu_exec_unrealizefn(CPUState *cpu)
     if (qdev_get_vmsd(DEVICE(cpu)) == NULL) {
         vmstate_unregister(NULL, &vmstate_cpu_common, cpu);
     }
+#ifndef CONFIG_USER_ONLY
+    tcg_iommu_free_notifier_list(cpu);
+#endif
 }
 
 Property cpu_common_props[] = {
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [Qemu-devel] [PATCH 18/27] hw/misc/tz-mpc.c: Implement the Arm TrustZone Memory Protection Controller
  2018-05-21 14:03 [Qemu-devel] [PATCH 00/27] iommu: support txattrs, support TCG execution, implement TZ MPC Peter Maydell
                   ` (16 preceding siblings ...)
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 17/27] exec.c: Handle IOMMUs in address_space_translate_for_iotlb() Peter Maydell
@ 2018-05-21 14:03 ` Peter Maydell
  2018-05-22 11:30   ` Auger Eric
  2018-05-23 10:41   ` Alex Bennée
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 19/27] hw/misc/tz-mpc.c: Implement registers Peter Maydell
                   ` (10 subsequent siblings)
  28 siblings, 2 replies; 114+ messages in thread
From: Peter Maydell @ 2018-05-21 14:03 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: patches, Paolo Bonzini, Richard Henderson, Alex Bennée

Implement the Arm TrustZone Memory Protection Controller, which sits
in front of RAM and allows secure software to configure it to either
pass through or reject transactions.

We implement the MPC as a QEMU IOMMU, which will direct transactions
either through to the devices and memory behind it or to a special
"never works" AddressSpace if they are blocked.

This initial commit implements the skeleton of the device:
 * it always permits accesses
 * it doesn't implement most of the registers
 * it doesn't implement the interrupt or other behaviour
   for blocked transactions

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/misc/Makefile.objs           |   1 +
 include/hw/misc/tz-mpc.h        |  70 ++++++
 hw/misc/tz-mpc.c                | 381 ++++++++++++++++++++++++++++++++
 MAINTAINERS                     |   2 +
 default-configs/arm-softmmu.mak |   1 +
 hw/misc/trace-events            |   7 +
 6 files changed, 462 insertions(+)
 create mode 100644 include/hw/misc/tz-mpc.h
 create mode 100644 hw/misc/tz-mpc.c

diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
index 00e834d0f0..7295e676a6 100644
--- a/hw/misc/Makefile.objs
+++ b/hw/misc/Makefile.objs
@@ -61,6 +61,7 @@ obj-$(CONFIG_MIPS_ITU) += mips_itu.o
 obj-$(CONFIG_MPS2_FPGAIO) += mps2-fpgaio.o
 obj-$(CONFIG_MPS2_SCC) += mps2-scc.o
 
+obj-$(CONFIG_TZ_MPC) += tz-mpc.o
 obj-$(CONFIG_TZ_PPC) += tz-ppc.o
 obj-$(CONFIG_IOTKIT_SECCTL) += iotkit-secctl.o
 
diff --git a/include/hw/misc/tz-mpc.h b/include/hw/misc/tz-mpc.h
new file mode 100644
index 0000000000..b5eaf1699e
--- /dev/null
+++ b/include/hw/misc/tz-mpc.h
@@ -0,0 +1,70 @@
+/*
+ * ARM TrustZone memory protection controller emulation
+ *
+ * Copyright (c) 2018 Linaro Limited
+ * Written by Peter Maydell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 or
+ * (at your option) any later version.
+ */
+
+/* This is a model of the TrustZone memory protection controller (MPC).
+ * It is documented in the ARM CoreLink SIE-200 System IP for Embedded TRM
+ * (DDI 0571G):
+ * https://developer.arm.com/products/architecture/m-profile/docs/ddi0571/g
+ *
+ * The MPC sits in front of memory and allows secure software to
+ * configure it to either pass through or reject transactions.
+ * Rejected transactions may be configured to either be aborted, or to
+ * behave as RAZ/WI. An interrupt can be signalled for a rejected transaction.
+ *
+ * The MPC has a register interface which the guest uses to configure it.
+ *
+ * QEMU interface:
+ * + sysbus MMIO region 0: MemoryRegion for the MPC's config registers
+ * + sysbus MMIO region 1: MemoryRegion for the upstream end of the MPC
+ * + Property "downstream": MemoryRegion defining the downstream memory
+ * + Named GPIO output "irq": set for a transaction-failed interrupt
+ */
+
+#ifndef TZ_MPC_H
+#define TZ_MPC_H
+
+#include "hw/sysbus.h"
+
+#define TYPE_TZ_MPC "tz-mpc"
+#define TZ_MPC(obj) OBJECT_CHECK(TZMPC, (obj), TYPE_TZ_MPC)
+
+#define TZ_NUM_PORTS 16
+
+#define TYPE_TZ_MPC_IOMMU_MEMORY_REGION "tz-mpc-iommu-memory-region"
+
+typedef struct TZMPC TZMPC;
+
+struct TZMPC {
+    /*< private >*/
+    SysBusDevice parent_obj;
+
+    /*< public >*/
+
+    qemu_irq irq;
+
+    /* Properties */
+    MemoryRegion *downstream;
+
+    hwaddr blocksize;
+    uint32_t blk_max;
+
+    /* MemoryRegions exposed to user */
+    MemoryRegion regmr;
+    IOMMUMemoryRegion upstream;
+
+    /* MemoryRegion used internally */
+    MemoryRegion blocked_io;
+
+    AddressSpace downstream_as;
+    AddressSpace blocked_io_as;
+};
+
+#endif
diff --git a/hw/misc/tz-mpc.c b/hw/misc/tz-mpc.c
new file mode 100644
index 0000000000..d4467ccc3b
--- /dev/null
+++ b/hw/misc/tz-mpc.c
@@ -0,0 +1,381 @@
+/*
+ * ARM TrustZone memory protection controller emulation
+ *
+ * Copyright (c) 2018 Linaro Limited
+ * Written by Peter Maydell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 or
+ * (at your option) any later version.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "qapi/error.h"
+#include "trace.h"
+#include "hw/sysbus.h"
+#include "hw/registerfields.h"
+#include "hw/misc/tz-mpc.h"
+
+/* Our IOMMU has two IOMMU indexes, one for secure transactions and one for
+ * non-secure transactions.
+ */
+enum {
+    IOMMU_IDX_S,
+    IOMMU_IDX_NS,
+    IOMMU_NUM_INDEXES,
+};
+
+/* Config registers */
+REG32(CTRL, 0x00)
+REG32(BLK_MAX, 0x10)
+REG32(BLK_CFG, 0x14)
+REG32(BLK_IDX, 0x18)
+REG32(BLK_LUT, 0x1c)
+REG32(INT_STAT, 0x20)
+REG32(INT_CLEAR, 0x24)
+REG32(INT_EN, 0x28)
+REG32(INT_INFO1, 0x2c)
+REG32(INT_INFO2, 0x30)
+REG32(INT_SET, 0x34)
+REG32(PIDR4, 0xfd0)
+REG32(PIDR5, 0xfd4)
+REG32(PIDR6, 0xfd8)
+REG32(PIDR7, 0xfdc)
+REG32(PIDR0, 0xfe0)
+REG32(PIDR1, 0xfe4)
+REG32(PIDR2, 0xfe8)
+REG32(PIDR3, 0xfec)
+REG32(CIDR0, 0xff0)
+REG32(CIDR1, 0xff4)
+REG32(CIDR2, 0xff8)
+REG32(CIDR3, 0xffc)
+
+static const uint8_t tz_mpc_idregs[] = {
+    0x04, 0x00, 0x00, 0x00,
+    0x60, 0xb8, 0x1b, 0x00,
+    0x0d, 0xf0, 0x05, 0xb1,
+};
+
+static MemTxResult tz_mpc_reg_read(void *opaque, hwaddr addr,
+                                   uint64_t *pdata,
+                                   unsigned size, MemTxAttrs attrs)
+{
+    uint64_t r;
+    uint32_t offset = addr & ~0x3;
+
+    switch (offset) {
+    case A_PIDR4:
+    case A_PIDR5:
+    case A_PIDR6:
+    case A_PIDR7:
+    case A_PIDR0:
+    case A_PIDR1:
+    case A_PIDR2:
+    case A_PIDR3:
+    case A_CIDR0:
+    case A_CIDR1:
+    case A_CIDR2:
+    case A_CIDR3:
+        r = tz_mpc_idregs[(offset - A_PIDR4) / 4];
+        break;
+    case A_INT_CLEAR:
+    case A_INT_SET:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "TZ MPC register read: write-only offset 0x%x\n",
+                      offset);
+        r = 0;
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "TZ MPC register read: bad offset 0x%x\n", offset);
+        r = 0;
+        break;
+    }
+
+    if (size != 4) {
+        /* None of our registers are read-sensitive (except BLK_LUT,
+         * which can special case the "size not 4" case), so just
+         * pull the right bytes out of the word read result.
+         */
+        r = extract32(r, (addr & 3) * 8, size * 8);
+    }
+
+    trace_tz_mpc_reg_read(addr, r, size);
+    *pdata = r;
+    return MEMTX_OK;
+}
+
+static MemTxResult tz_mpc_reg_write(void *opaque, hwaddr addr,
+                                    uint64_t value,
+                                    unsigned size, MemTxAttrs attrs)
+{
+    uint32_t offset = addr & ~0x3;
+
+    trace_tz_mpc_reg_write(addr, value, size);
+
+    if (size != 4) {
+        /* Expand the byte or halfword write to a full word size.
+         * In most cases we can do this with zeroes; the exceptions
+         * are CTRL, BLK_IDX and BLK_LUT.
+         */
+        uint32_t oldval;
+
+        switch (offset) {
+            /* As we add support for registers which need expansions
+             * other than zeroes we'll fill in cases here.
+             */
+        default:
+            oldval = 0;
+            break;
+        }
+        value = deposit32(oldval, (addr & 3) * 8, size * 8, value);
+    }
+
+    switch (offset) {
+    case A_PIDR4:
+    case A_PIDR5:
+    case A_PIDR6:
+    case A_PIDR7:
+    case A_PIDR0:
+    case A_PIDR1:
+    case A_PIDR2:
+    case A_PIDR3:
+    case A_CIDR0:
+    case A_CIDR1:
+    case A_CIDR2:
+    case A_CIDR3:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "TZ MPC register write: read-only offset 0x%x\n", offset);
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "TZ MPC register write: bad offset 0x%x\n", offset);
+        break;
+    }
+
+    return MEMTX_OK;
+}
+
+static const MemoryRegionOps tz_mpc_reg_ops = {
+    .read_with_attrs = tz_mpc_reg_read,
+    .write_with_attrs = tz_mpc_reg_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid.min_access_size = 1,
+    .valid.max_access_size = 4,
+    .impl.min_access_size = 1,
+    .impl.max_access_size = 4,
+};
+
+/* Accesses only reach these read and write functions if the MPC is
+ * blocking them; non-blocked accesses go directly to the downstream
+ * memory region without passing through this code.
+ */
+static MemTxResult tz_mpc_mem_blocked_read(void *opaque, hwaddr addr,
+                                           uint64_t *pdata,
+                                           unsigned size, MemTxAttrs attrs)
+{
+    trace_tz_mpc_mem_blocked_read(addr, size, attrs.secure);
+
+    *pdata = 0;
+    return MEMTX_OK;
+}
+
+static MemTxResult tz_mpc_mem_blocked_write(void *opaque, hwaddr addr,
+                                            uint64_t value,
+                                            unsigned size, MemTxAttrs attrs)
+{
+    trace_tz_mpc_mem_blocked_write(addr, value, size, attrs.secure);
+
+    return MEMTX_OK;
+}
+
+static const MemoryRegionOps tz_mpc_mem_blocked_ops = {
+    .read_with_attrs = tz_mpc_mem_blocked_read,
+    .write_with_attrs = tz_mpc_mem_blocked_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid.min_access_size = 1,
+    .valid.max_access_size = 8,
+    .impl.min_access_size = 1,
+    .impl.max_access_size = 8,
+};
+
+static IOMMUTLBEntry tz_mpc_translate(IOMMUMemoryRegion *iommu,
+                                      hwaddr addr, IOMMUAccessFlags flags,
+                                      int iommu_idx)
+{
+    TZMPC *s = TZ_MPC(container_of(iommu, TZMPC, upstream));
+    bool ok;
+
+    IOMMUTLBEntry ret = {
+        .iova = addr & ~(s->blocksize - 1),
+        .translated_addr = addr & ~(s->blocksize - 1),
+        .addr_mask = s->blocksize - 1,
+        .perm = IOMMU_RW,
+    };
+
+    /* Look at the per-block configuration for this address, and
+     * return a TLB entry directing the transaction at either
+     * downstream_as or blocked_io_as, as appropriate.
+     * For the moment, always permit accesses.
+     */
+    ok = true;
+
+    trace_tz_mpc_translate(addr, flags,
+                           iommu_idx == IOMMU_IDX_S ? "S" : "NS",
+                           ok ? "pass" : "block");
+
+    ret.target_as = ok ? &s->downstream_as : &s->blocked_io_as;
+    return ret;
+}
+
+static int tz_mpc_attrs_to_index(IOMMUMemoryRegion *iommu, MemTxAttrs attrs)
+{
+    /* We treat unspecified attributes like secure. Transactions with
+     * unspecified attributes come from places like
+     * cpu_physical_memory_write_rom() for initial image load, and we want
+     * those to pass through the from-reset "everything is secure" config.
+     * All the real during-emulation transactions from the CPU will
+     * specify attributes.
+     */
+    return (attrs.unspecified || attrs.secure) ? IOMMU_IDX_S : IOMMU_IDX_NS;
+}
+
+static int tz_mpc_num_indexes(IOMMUMemoryRegion *iommu)
+{
+    return IOMMU_NUM_INDEXES;
+}
+
+static void tz_mpc_reset(DeviceState *dev)
+{
+}
+
+static void tz_mpc_init(Object *obj)
+{
+    DeviceState *dev = DEVICE(obj);
+    TZMPC *s = TZ_MPC(obj);
+
+    qdev_init_gpio_out_named(dev, &s->irq, "irq", 1);
+}
+
+static void tz_mpc_realize(DeviceState *dev, Error **errp)
+{
+    Object *obj = OBJECT(dev);
+    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+    TZMPC *s = TZ_MPC(dev);
+    uint64_t size;
+
+    /* We can't create the upstream end of the port until realize,
+     * as we don't know the size of the MR used as the downstream until then.
+     * We insist on having a downstream, to avoid complicating the code
+     * with handling the "don't know how big this is" case. It's easy
+     * enough for the user to create an unimplemented_device as downstream
+     * if they have nothing else to plug into this.
+     */
+    if (!s->downstream) {
+        error_setg(errp, "MPC 'downstream' link not set");
+        return;
+    }
+
+    size = memory_region_size(s->downstream);
+
+    memory_region_init_iommu(&s->upstream, sizeof(s->upstream),
+                             TYPE_TZ_MPC_IOMMU_MEMORY_REGION,
+                             obj, "tz-mpc-upstream", size);
+
+    /* In real hardware the block size is configurable. In QEMU we could
+     * make it configurable but will need it to be at least as big as the
+     * target page size so we can execute out of the resulting MRs. Guest
+     * software is supposed to check the block size using the BLK_CFG
+     * register, so make it fixed at the page size.
+     */
+    s->blocksize = memory_region_iommu_get_min_page_size(&s->upstream);
+    if (size % s->blocksize != 0) {
+        error_setg(errp,
+                   "MPC 'downstream' size %" PRId64
+                   " is not a multiple of %" HWADDR_PRIx " bytes",
+                   size, s->blocksize);
+        object_unref(OBJECT(&s->upstream));
+        return;
+    }
+
+    /* BLK_MAX is the max value of BLK_IDX, which indexes an array of 32-bit
+     * words, each bit of which indicates one block.
+     */
+    s->blk_max = DIV_ROUND_UP(size / s->blocksize, 32);
+
+    memory_region_init_io(&s->regmr, obj, &tz_mpc_reg_ops,
+                          s, "tz-mpc-regs", 0x1000);
+    sysbus_init_mmio(sbd, &s->regmr);
+
+    sysbus_init_mmio(sbd, MEMORY_REGION(&s->upstream));
+
+    /* This memory region is not exposed to users of this device as a
+     * sysbus MMIO region, but is instead used internally as something
+     * that our IOMMU translate function might direct accesses to.
+     */
+    memory_region_init_io(&s->blocked_io, obj, &tz_mpc_mem_blocked_ops,
+                          s, "tz-mpc-blocked-io", size);
+
+    address_space_init(&s->downstream_as, s->downstream,
+                       "tz-mpc-downstream");
+    address_space_init(&s->blocked_io_as, &s->blocked_io,
+                       "tz-mpc-blocked-io");
+}
+
+static const VMStateDescription tz_mpc_vmstate = {
+    .name = "tz-mpc",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static Property tz_mpc_properties[] = {
+    DEFINE_PROP_LINK("downstream", TZMPC, downstream,
+                     TYPE_MEMORY_REGION, MemoryRegion *),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void tz_mpc_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->realize = tz_mpc_realize;
+    dc->vmsd = &tz_mpc_vmstate;
+    dc->reset = tz_mpc_reset;
+    dc->props = tz_mpc_properties;
+}
+
+static const TypeInfo tz_mpc_info = {
+    .name = TYPE_TZ_MPC,
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(TZMPC),
+    .instance_init = tz_mpc_init,
+    .class_init = tz_mpc_class_init,
+};
+
+static void tz_mpc_iommu_memory_region_class_init(ObjectClass *klass,
+                                                  void *data)
+{
+    IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass);
+
+    imrc->translate = tz_mpc_translate;
+    imrc->attrs_to_index = tz_mpc_attrs_to_index;
+    imrc->num_indexes = tz_mpc_num_indexes;
+}
+
+static const TypeInfo tz_mpc_iommu_memory_region_info = {
+    .name = TYPE_TZ_MPC_IOMMU_MEMORY_REGION,
+    .parent = TYPE_IOMMU_MEMORY_REGION,
+    .class_init = tz_mpc_iommu_memory_region_class_init,
+};
+
+static void tz_mpc_register_types(void)
+{
+    type_register_static(&tz_mpc_info);
+    type_register_static(&tz_mpc_iommu_memory_region_info);
+}
+
+type_init(tz_mpc_register_types);
diff --git a/MAINTAINERS b/MAINTAINERS
index 1823f900b9..9cddb699df 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -449,6 +449,8 @@ F: hw/char/cmsdk-apb-uart.c
 F: include/hw/char/cmsdk-apb-uart.h
 F: hw/misc/tz-ppc.c
 F: include/hw/misc/tz-ppc.h
+F: hw/misc/tz-mpc.c
+F: include/hw/misc/tz-mpc.h
 
 ARM cores
 M: Peter Maydell <peter.maydell@linaro.org>
diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index dd29e741c2..30e73847ac 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -106,6 +106,7 @@ CONFIG_CMSDK_APB_UART=y
 CONFIG_MPS2_FPGAIO=y
 CONFIG_MPS2_SCC=y
 
+CONFIG_TZ_MPC=y
 CONFIG_TZ_PPC=y
 CONFIG_IOTKIT=y
 CONFIG_IOTKIT_SECCTL=y
diff --git a/hw/misc/trace-events b/hw/misc/trace-events
index 562d9ed005..d4835c8970 100644
--- a/hw/misc/trace-events
+++ b/hw/misc/trace-events
@@ -84,6 +84,13 @@ mos6522_set_sr_int(void) "set sr_int"
 mos6522_write(uint64_t addr, uint64_t val) "reg=0x%"PRIx64 " val=0x%"PRIx64
 mos6522_read(uint64_t addr, unsigned val) "reg=0x%"PRIx64 " val=0x%x"
 
+# hw/misc/tz-mpc.c
+tz_mpc_reg_read(uint32_t offset, uint64_t data, unsigned size) "TZ MPC regs read: offset 0x%x data 0x%" PRIx64 " size %u"
+tz_mpc_reg_write(uint32_t offset, uint64_t data, unsigned size) "TZ MPC regs write: offset 0x%x data 0x%" PRIx64 " size %u"
+tz_mpc_mem_blocked_read(uint64_t addr, unsigned size, bool secure) "TZ MPC blocked read: offset 0x%" PRIx64 " size %u secure %d"
+tz_mpc_mem_blocked_write(uint64_t addr, uint64_t data, unsigned size, bool secure) "TZ MPC blocked write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d"
+tz_mpc_translate(uint64_t addr, int flags, const char *idx, const char *res) "TZ MPC translate: addr 0x%" PRIx64 " flags 0x%x iommu_idx %s: %s"
+
 # hw/misc/tz-ppc.c
 tz_ppc_reset(void) "TZ PPC: reset"
 tz_ppc_cfg_nonsec(int n, int level) "TZ PPC: cfg_nonsec[%d] = %d"
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [Qemu-devel] [PATCH 19/27] hw/misc/tz-mpc.c: Implement registers
  2018-05-21 14:03 [Qemu-devel] [PATCH 00/27] iommu: support txattrs, support TCG execution, implement TZ MPC Peter Maydell
                   ` (17 preceding siblings ...)
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 18/27] hw/misc/tz-mpc.c: Implement the Arm TrustZone Memory Protection Controller Peter Maydell
@ 2018-05-21 14:03 ` Peter Maydell
  2018-05-23 10:44   ` Alex Bennée
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 20/27] hw/misc/tz-mpc.c: Implement correct blocked-access behaviour Peter Maydell
                   ` (9 subsequent siblings)
  28 siblings, 1 reply; 114+ messages in thread
From: Peter Maydell @ 2018-05-21 14:03 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: patches, Paolo Bonzini, Richard Henderson, Alex Bennée

Implement the missing registers for the TZ MPC.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 include/hw/misc/tz-mpc.h |  10 +++
 hw/misc/tz-mpc.c         | 137 ++++++++++++++++++++++++++++++++++++++-
 2 files changed, 144 insertions(+), 3 deletions(-)

diff --git a/include/hw/misc/tz-mpc.h b/include/hw/misc/tz-mpc.h
index b5eaf1699e..1fff4d6029 100644
--- a/include/hw/misc/tz-mpc.h
+++ b/include/hw/misc/tz-mpc.h
@@ -48,6 +48,16 @@ struct TZMPC {
 
     /*< public >*/
 
+    /* State */
+    uint32_t ctrl;
+    uint32_t blk_idx;
+    uint32_t int_stat;
+    uint32_t int_en;
+    uint32_t int_info1;
+    uint32_t int_info2;
+
+    uint32_t *blk_lut;
+
     qemu_irq irq;
 
     /* Properties */
diff --git a/hw/misc/tz-mpc.c b/hw/misc/tz-mpc.c
index d4467ccc3b..93453cbef2 100644
--- a/hw/misc/tz-mpc.c
+++ b/hw/misc/tz-mpc.c
@@ -28,16 +28,23 @@ enum {
 
 /* Config registers */
 REG32(CTRL, 0x00)
+    FIELD(CTRL, SEC_RESP, 4, 1)
+    FIELD(CTRL, AUTOINC, 8, 1)
+    FIELD(CTRL, LOCKDOWN, 31, 1)
 REG32(BLK_MAX, 0x10)
 REG32(BLK_CFG, 0x14)
 REG32(BLK_IDX, 0x18)
 REG32(BLK_LUT, 0x1c)
 REG32(INT_STAT, 0x20)
+    FIELD(INT_STAT, IRQ, 0, 1)
 REG32(INT_CLEAR, 0x24)
+    FIELD(INT_CLEAR, IRQ, 0, 1)
 REG32(INT_EN, 0x28)
+    FIELD(INT_EN, IRQ, 0, 1)
 REG32(INT_INFO1, 0x2c)
 REG32(INT_INFO2, 0x30)
 REG32(INT_SET, 0x34)
+    FIELD(INT_SET, IRQ, 0, 1)
 REG32(PIDR4, 0xfd0)
 REG32(PIDR5, 0xfd4)
 REG32(PIDR6, 0xfd8)
@@ -57,14 +64,55 @@ static const uint8_t tz_mpc_idregs[] = {
     0x0d, 0xf0, 0x05, 0xb1,
 };
 
+static void tz_mpc_irq_update(TZMPC *s)
+{
+    qemu_set_irq(s->irq, s->int_stat && s->int_en);
+}
+
 static MemTxResult tz_mpc_reg_read(void *opaque, hwaddr addr,
                                    uint64_t *pdata,
                                    unsigned size, MemTxAttrs attrs)
 {
+    TZMPC *s = TZ_MPC(opaque);
     uint64_t r;
     uint32_t offset = addr & ~0x3;
 
     switch (offset) {
+    case A_CTRL:
+        r = s->ctrl;
+        break;
+    case A_BLK_MAX:
+        r = s->blk_max;
+        break;
+    case A_BLK_CFG:
+        /* We are never in "init in progress state", so this just indicates
+         * the block size. s->blocksize == (1 << BLK_CFG + 5), so
+         * BLK_CFG == ctz32(s->blocksize) - 5
+         */
+        r = ctz32(s->blocksize) - 5;
+        break;
+    case A_BLK_IDX:
+        r = s->blk_idx;
+        break;
+    case A_BLK_LUT:
+        r = s->blk_lut[s->blk_idx];
+        if (size == 4) {
+            s->blk_idx++;
+            s->blk_idx %= s->blk_max;
+        }
+        break;
+    case A_INT_STAT:
+        r = s->int_stat;
+        break;
+    case A_INT_EN:
+        r = s->int_en;
+        break;
+    case A_INT_INFO1:
+        r = s->int_info1;
+        break;
+    case A_INT_INFO2:
+        r = s->int_info2;
+        break;
     case A_PIDR4:
     case A_PIDR5:
     case A_PIDR6:
@@ -110,6 +158,7 @@ static MemTxResult tz_mpc_reg_write(void *opaque, hwaddr addr,
                                     uint64_t value,
                                     unsigned size, MemTxAttrs attrs)
 {
+    TZMPC *s = TZ_MPC(opaque);
     uint32_t offset = addr & ~0x3;
 
     trace_tz_mpc_reg_write(addr, value, size);
@@ -122,9 +171,15 @@ static MemTxResult tz_mpc_reg_write(void *opaque, hwaddr addr,
         uint32_t oldval;
 
         switch (offset) {
-            /* As we add support for registers which need expansions
-             * other than zeroes we'll fill in cases here.
-             */
+        case A_CTRL:
+            oldval = s->ctrl;
+            break;
+        case A_BLK_IDX:
+            oldval = s->blk_idx;
+            break;
+        case A_BLK_LUT:
+            oldval = s->blk_lut[s->blk_idx];
+            break;
         default:
             oldval = 0;
             break;
@@ -132,7 +187,51 @@ static MemTxResult tz_mpc_reg_write(void *opaque, hwaddr addr,
         value = deposit32(oldval, (addr & 3) * 8, size * 8, value);
     }
 
+    if ((s->ctrl & R_CTRL_LOCKDOWN_MASK) &&
+        (offset == A_CTRL || offset == A_BLK_LUT || offset == A_INT_EN)) {
+        /* Lockdown mode makes these three registers read-only, and
+         * the only way out of it is to reset the device.
+         */
+        qemu_log_mask(LOG_GUEST_ERROR, "TZ MPC register write to offset 0x%x "
+                      "while MPC is in lockdown mode\n", offset);
+        return MEMTX_OK;
+    }
+
     switch (offset) {
+    case A_CTRL:
+        /* We don't implement the 'data gating' feature so all other bits
+         * are reserved and we make them RAZ/WI.
+         */
+        s->ctrl = value & (R_CTRL_SEC_RESP_MASK |
+                           R_CTRL_AUTOINC_MASK |
+                           R_CTRL_LOCKDOWN_MASK);
+        break;
+    case A_BLK_IDX:
+        s->blk_idx = value % s->blk_max;
+        break;
+    case A_BLK_LUT:
+        s->blk_lut[s->blk_idx] = value;
+        if (size == 4) {
+            s->blk_idx++;
+            s->blk_idx %= s->blk_max;
+        }
+        break;
+    case A_INT_CLEAR:
+        if (value & R_INT_CLEAR_IRQ_MASK) {
+            s->int_stat = 0;
+            tz_mpc_irq_update(s);
+        }
+        break;
+    case A_INT_EN:
+        s->int_en = value & R_INT_EN_IRQ_MASK;
+        tz_mpc_irq_update(s);
+        break;
+    case A_INT_SET:
+        if (value & R_INT_SET_IRQ_MASK) {
+            s->int_stat = R_INT_STAT_IRQ_MASK;
+            tz_mpc_irq_update(s);
+        }
+        break;
     case A_PIDR4:
     case A_PIDR5:
     case A_PIDR6:
@@ -248,6 +347,16 @@ static int tz_mpc_num_indexes(IOMMUMemoryRegion *iommu)
 
 static void tz_mpc_reset(DeviceState *dev)
 {
+    TZMPC *s = TZ_MPC(dev);
+
+    s->ctrl = 0;
+    s->blk_idx = 0;
+    s->int_stat = 0;
+    s->int_en = 0;
+    s->int_info1 = 0;
+    s->int_info2 = 0;
+
+    memset(s->blk_lut, 0, s->blk_max * sizeof(uint32_t));
 }
 
 static void tz_mpc_init(Object *obj)
@@ -321,13 +430,35 @@ static void tz_mpc_realize(DeviceState *dev, Error **errp)
                        "tz-mpc-downstream");
     address_space_init(&s->blocked_io_as, &s->blocked_io,
                        "tz-mpc-blocked-io");
+
+    s->blk_lut = g_new(uint32_t, s->blk_max);
+}
+
+static int tz_mpc_post_load(void *opaque, int version_id)
+{
+    TZMPC *s = TZ_MPC(opaque);
+
+    /* Check the incoming data doesn't point blk_idx off the end of blk_lut. */
+    if (s->blk_idx >= s->blk_max) {
+        return -1;
+    }
+    return 0;
 }
 
 static const VMStateDescription tz_mpc_vmstate = {
     .name = "tz-mpc",
     .version_id = 1,
     .minimum_version_id = 1,
+    .post_load = tz_mpc_post_load,
     .fields = (VMStateField[]) {
+        VMSTATE_UINT32(ctrl, TZMPC),
+        VMSTATE_UINT32(blk_idx, TZMPC),
+        VMSTATE_UINT32(int_stat, TZMPC),
+        VMSTATE_UINT32(int_en, TZMPC),
+        VMSTATE_UINT32(int_info1, TZMPC),
+        VMSTATE_UINT32(int_info2, TZMPC),
+        VMSTATE_VARRAY_UINT32(blk_lut, TZMPC, blk_max,
+                              0, vmstate_info_uint32, uint32_t),
         VMSTATE_END_OF_LIST()
     }
 };
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [Qemu-devel] [PATCH 20/27] hw/misc/tz-mpc.c: Implement correct blocked-access behaviour
  2018-05-21 14:03 [Qemu-devel] [PATCH 00/27] iommu: support txattrs, support TCG execution, implement TZ MPC Peter Maydell
                   ` (18 preceding siblings ...)
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 19/27] hw/misc/tz-mpc.c: Implement registers Peter Maydell
@ 2018-05-21 14:03 ` Peter Maydell
  2018-05-23 10:49   ` Alex Bennée
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 21/27] hw/misc/tz_mpc.c: Honour the BLK_LUT settings in translate Peter Maydell
                   ` (8 subsequent siblings)
  28 siblings, 1 reply; 114+ messages in thread
From: Peter Maydell @ 2018-05-21 14:03 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: patches, Paolo Bonzini, Richard Henderson, Alex Bennée

The MPC is guest-configurable for whether blocked accesses:
 * should be RAZ/WI or cause a bus error
 * should generate an interrupt or not

Implement this behaviour in the blocked-access handlers.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/misc/tz-mpc.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 48 insertions(+), 2 deletions(-)

diff --git a/hw/misc/tz-mpc.c b/hw/misc/tz-mpc.c
index 93453cbef2..39a72563b7 100644
--- a/hw/misc/tz-mpc.c
+++ b/hw/misc/tz-mpc.c
@@ -43,6 +43,9 @@ REG32(INT_EN, 0x28)
     FIELD(INT_EN, IRQ, 0, 1)
 REG32(INT_INFO1, 0x2c)
 REG32(INT_INFO2, 0x30)
+    FIELD(INT_INFO2, HMASTER, 0, 16)
+    FIELD(INT_INFO2, HNONSEC, 16, 1)
+    FIELD(INT_INFO2, CFG_NS, 17, 1)
 REG32(INT_SET, 0x34)
     FIELD(INT_SET, IRQ, 0, 1)
 REG32(PIDR4, 0xfd0)
@@ -266,6 +269,45 @@ static const MemoryRegionOps tz_mpc_reg_ops = {
     .impl.max_access_size = 4,
 };
 
+static inline bool tz_mpc_cfg_ns(TZMPC *s, hwaddr addr)
+{
+    /* Return the cfg_ns bit from the LUT for the specified address */
+    hwaddr blknum = addr / s->blocksize;
+    hwaddr blkword = blknum / 32;
+    uint32_t blkbit = 1U << (blknum % 32);
+
+    /* This would imply the address was larger than the size we
+     * defined this memory region to be, so it can't happen.
+     */
+    assert(blkword < s->blk_max);
+    return s->blk_lut[blkword] & blkbit;
+}
+
+static MemTxResult tz_mpc_handle_block(TZMPC *s, hwaddr addr, MemTxAttrs attrs)
+{
+    /* Handle a blocked transaction: raise IRQ, capture info, etc */
+    if (!s->int_stat) {
+        /* First blocked transfer: capture information into INT_INFO1 and
+         * INT_INFO2. Subsequent transfers are still blocked but don't
+         * capture information until the guest clears the interrupt.
+         */
+
+        s->int_info1 = addr;
+        s->int_info2 = 0;
+        s->int_info2 = FIELD_DP32(s->int_info2, INT_INFO2, HMASTER,
+                                  attrs.requester_id & 0xffff);
+        s->int_info2 = FIELD_DP32(s->int_info2, INT_INFO2, HNONSEC,
+                                  ~attrs.secure);
+        s->int_info2 = FIELD_DP32(s->int_info2, INT_INFO2, CFG_NS,
+                                  tz_mpc_cfg_ns(s, addr));
+        s->int_stat |= R_INT_STAT_IRQ_MASK;
+        tz_mpc_irq_update(s);
+    }
+
+    /* Generate bus error if desired; otherwise RAZ/WI */
+    return (s->ctrl & R_CTRL_SEC_RESP_MASK) ? MEMTX_ERROR : MEMTX_OK;
+}
+
 /* Accesses only reach these read and write functions if the MPC is
  * blocking them; non-blocked accesses go directly to the downstream
  * memory region without passing through this code.
@@ -274,19 +316,23 @@ static MemTxResult tz_mpc_mem_blocked_read(void *opaque, hwaddr addr,
                                            uint64_t *pdata,
                                            unsigned size, MemTxAttrs attrs)
 {
+    TZMPC *s = TZ_MPC(opaque);
+
     trace_tz_mpc_mem_blocked_read(addr, size, attrs.secure);
 
     *pdata = 0;
-    return MEMTX_OK;
+    return tz_mpc_handle_block(s, addr, attrs);
 }
 
 static MemTxResult tz_mpc_mem_blocked_write(void *opaque, hwaddr addr,
                                             uint64_t value,
                                             unsigned size, MemTxAttrs attrs)
 {
+    TZMPC *s = TZ_MPC(opaque);
+
     trace_tz_mpc_mem_blocked_write(addr, value, size, attrs.secure);
 
-    return MEMTX_OK;
+    return tz_mpc_handle_block(s, addr, attrs);
 }
 
 static const MemoryRegionOps tz_mpc_mem_blocked_ops = {
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [Qemu-devel] [PATCH 21/27] hw/misc/tz_mpc.c: Honour the BLK_LUT settings in translate
  2018-05-21 14:03 [Qemu-devel] [PATCH 00/27] iommu: support txattrs, support TCG execution, implement TZ MPC Peter Maydell
                   ` (19 preceding siblings ...)
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 20/27] hw/misc/tz-mpc.c: Implement correct blocked-access behaviour Peter Maydell
@ 2018-05-21 14:03 ` Peter Maydell
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 22/27] vmstate.h: Provide VMSTATE_BOOL_SUB_ARRAY Peter Maydell
                   ` (7 subsequent siblings)
  28 siblings, 0 replies; 114+ messages in thread
From: Peter Maydell @ 2018-05-21 14:03 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: patches, Paolo Bonzini, Richard Henderson, Alex Bennée

The final part of the Memory Protection Controller we need to
implement is actually using the BLK_LUT data programmed by the
guest to determine whether to block the transaction or not.

Since this means we now change transaction mappings when
the guest writes to BLK_LUT, we must also call the IOMMU
notifiers at that point.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/misc/tz-mpc.c     | 50 ++++++++++++++++++++++++++++++++++++++++++--
 hw/misc/trace-events |  1 +
 2 files changed, 49 insertions(+), 2 deletions(-)

diff --git a/hw/misc/tz-mpc.c b/hw/misc/tz-mpc.c
index 39a72563b7..439f6b9496 100644
--- a/hw/misc/tz-mpc.c
+++ b/hw/misc/tz-mpc.c
@@ -72,6 +72,50 @@ static void tz_mpc_irq_update(TZMPC *s)
     qemu_set_irq(s->irq, s->int_stat && s->int_en);
 }
 
+static void tz_mpc_iommu_notify(TZMPC *s, uint32_t lutidx,
+                                uint32_t oldlut, uint32_t newlut)
+{
+    /* Called when the LUT word at lutidx has changed from oldlut to newlut;
+     * must call the IOMMU notifiers for the changed blocks.
+     */
+    IOMMUTLBEntry entry = {
+        .addr_mask = s->blocksize - 1,
+    };
+    hwaddr addr = lutidx * s->blocksize * 32;
+    int i;
+
+    for (i = 0; i < 32; i++, addr += s->blocksize) {
+        if (!((oldlut ^ newlut) & (1 << i))) {
+            continue;
+        }
+        /* This changes the mappings for both the S and the NS space,
+         * so we need to do four notifies: an UNMAP then a MAP for each.
+         */
+
+        trace_tz_mpc_iommu_notify(addr);
+        entry.iova = addr;
+        entry.translated_addr = addr;
+
+        entry.perm = IOMMU_NONE;
+        memory_region_notify_iommu(&s->upstream, IOMMU_IDX_S, entry);
+        memory_region_notify_iommu(&s->upstream, IOMMU_IDX_NS, entry);
+
+        entry.perm = IOMMU_RW;
+        if (newlut & (1 << i)) {
+            entry.target_as = &s->blocked_io_as;
+        } else {
+            entry.target_as = &s->downstream_as;
+        }
+        memory_region_notify_iommu(&s->upstream, IOMMU_IDX_S, entry);
+        if (newlut & (1 << i)) {
+            entry.target_as = &s->downstream_as;
+        } else {
+            entry.target_as = &s->blocked_io_as;
+        }
+        memory_region_notify_iommu(&s->upstream, IOMMU_IDX_NS, entry);
+    }
+}
+
 static MemTxResult tz_mpc_reg_read(void *opaque, hwaddr addr,
                                    uint64_t *pdata,
                                    unsigned size, MemTxAttrs attrs)
@@ -213,6 +257,7 @@ static MemTxResult tz_mpc_reg_write(void *opaque, hwaddr addr,
         s->blk_idx = value % s->blk_max;
         break;
     case A_BLK_LUT:
+        tz_mpc_iommu_notify(s, s->blk_idx, s->blk_lut[s->blk_idx], value);
         s->blk_lut[s->blk_idx] = value;
         if (size == 4) {
             s->blk_idx++;
@@ -362,9 +407,10 @@ static IOMMUTLBEntry tz_mpc_translate(IOMMUMemoryRegion *iommu,
     /* Look at the per-block configuration for this address, and
      * return a TLB entry directing the transaction at either
      * downstream_as or blocked_io_as, as appropriate.
-     * For the moment, always permit accesses.
+     * If the LUT cfg_ns bit is 1, only non-secure transactions
+     * may pass. If the bit is 0, only secure transactions may pass.
      */
-    ok = true;
+    ok = tz_mpc_cfg_ns(s, addr) == (iommu_idx == IOMMU_IDX_NS);
 
     trace_tz_mpc_translate(addr, flags,
                            iommu_idx == IOMMU_IDX_S ? "S" : "NS",
diff --git a/hw/misc/trace-events b/hw/misc/trace-events
index d4835c8970..be3ee1707b 100644
--- a/hw/misc/trace-events
+++ b/hw/misc/trace-events
@@ -90,6 +90,7 @@ tz_mpc_reg_write(uint32_t offset, uint64_t data, unsigned size) "TZ MPC regs wri
 tz_mpc_mem_blocked_read(uint64_t addr, unsigned size, bool secure) "TZ MPC blocked read: offset 0x%" PRIx64 " size %u secure %d"
 tz_mpc_mem_blocked_write(uint64_t addr, uint64_t data, unsigned size, bool secure) "TZ MPC blocked write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d"
 tz_mpc_translate(uint64_t addr, int flags, const char *idx, const char *res) "TZ MPC translate: addr 0x%" PRIx64 " flags 0x%x iommu_idx %s: %s"
+tz_mpc_iommu_notify(uint64_t addr) "TZ MPC iommu: notifying UNMAP/MAP for 0x%" PRIx64
 
 # hw/misc/tz-ppc.c
 tz_ppc_reset(void) "TZ PPC: reset"
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [Qemu-devel] [PATCH 22/27] vmstate.h: Provide VMSTATE_BOOL_SUB_ARRAY
  2018-05-21 14:03 [Qemu-devel] [PATCH 00/27] iommu: support txattrs, support TCG execution, implement TZ MPC Peter Maydell
                   ` (20 preceding siblings ...)
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 21/27] hw/misc/tz_mpc.c: Honour the BLK_LUT settings in translate Peter Maydell
@ 2018-05-21 14:03 ` Peter Maydell
  2018-05-23 11:01   ` Alex Bennée
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 23/27] hw/core/or-irq: Support more than 16 inputs to an OR gate Peter Maydell
                   ` (6 subsequent siblings)
  28 siblings, 1 reply; 114+ messages in thread
From: Peter Maydell @ 2018-05-21 14:03 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: patches, Paolo Bonzini, Richard Henderson, Alex Bennée

Provide a VMSTATE_BOOL_SUB_ARRAY to go with VMSTATE_UINT8_SUB_ARRAY
and friends.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 include/migration/vmstate.h | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
index df463fd33d..59fc75e418 100644
--- a/include/migration/vmstate.h
+++ b/include/migration/vmstate.h
@@ -870,6 +870,9 @@ extern const VMStateInfo vmstate_info_qtailq;
 #define VMSTATE_BOOL_ARRAY(_f, _s, _n)                               \
     VMSTATE_BOOL_ARRAY_V(_f, _s, _n, 0)
 
+#define VMSTATE_BOOL_SUB_ARRAY(_f, _s, _start, _num)                \
+    VMSTATE_SUB_ARRAY(_f, _s, _start, _num, 0, vmstate_info_bool, bool)
+
 #define VMSTATE_UINT16_ARRAY_V(_f, _s, _n, _v)                         \
     VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_uint16, uint16_t)
 
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [Qemu-devel] [PATCH 23/27] hw/core/or-irq: Support more than 16 inputs to an OR gate
  2018-05-21 14:03 [Qemu-devel] [PATCH 00/27] iommu: support txattrs, support TCG execution, implement TZ MPC Peter Maydell
                   ` (21 preceding siblings ...)
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 22/27] vmstate.h: Provide VMSTATE_BOOL_SUB_ARRAY Peter Maydell
@ 2018-05-21 14:03 ` Peter Maydell
  2018-05-21 14:34   ` Paolo Bonzini
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 24/27] hw/misc/iotkit-secctl.c: Implement SECMPCINTSTATUS Peter Maydell
                   ` (5 subsequent siblings)
  28 siblings, 1 reply; 114+ messages in thread
From: Peter Maydell @ 2018-05-21 14:03 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: patches, Paolo Bonzini, Richard Henderson, Alex Bennée

For the IoTKit MPC support, we need to wire together the
interrupt outputs of 17 MPCs; this exceeds the current
value of MAX_OR_LINES. Increase MAX_OR_LINES to 32 (which
should be enough for anyone).

The tricky part is retaining the migration compatibility for
existing OR gates; we add a subsection which is only used
for larger OR gates, and define it such that we can freely
increase MAX_OR_LINES in future (or even move to a dynamically
allocated levels[] array without an upper size limit) without
breaking compatibility.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 include/hw/or-irq.h |  5 ++++-
 hw/core/or-irq.c    | 39 +++++++++++++++++++++++++++++++++++++--
 2 files changed, 41 insertions(+), 3 deletions(-)

diff --git a/include/hw/or-irq.h b/include/hw/or-irq.h
index 3f6fc1b58a..5a31e5a188 100644
--- a/include/hw/or-irq.h
+++ b/include/hw/or-irq.h
@@ -31,7 +31,10 @@
 
 #define TYPE_OR_IRQ "or-irq"
 
-#define MAX_OR_LINES      16
+/* This can safely be increased if necessary without breaking
+ * migration compatibility (as long as it remains greater than 15).
+ */
+#define MAX_OR_LINES      32
 
 typedef struct OrIRQState qemu_or_irq;
 
diff --git a/hw/core/or-irq.c b/hw/core/or-irq.c
index f9d76c4641..a86901b673 100644
--- a/hw/core/or-irq.c
+++ b/hw/core/or-irq.c
@@ -66,14 +66,49 @@ static void or_irq_init(Object *obj)
     qdev_init_gpio_out(DEVICE(obj), &s->out_irq, 1);
 }
 
+/* The original version of this device had a fixed 16 entries in its
+ * VMState array; devices with more inputs than this need to
+ * migrate the extra lines via a subsection.
+ * The subsection migrates as much of the levels[] array as is needed
+ * (including repeating the first 16 elements), to avoid the awkwardness
+ * of splitting it in two to meet the requirements of VMSTATE_VARRAY_UINT16.
+ */
+#define OLD_MAX_OR_LINES 16
+#if MAX_OR_LINES < OLD_MAX_OR_LINES
+#error MAX_OR_LINES must be at least 16 for migration compatibility
+#endif
+
+static bool vmstate_extras_needed(void *opaque)
+{
+    qemu_or_irq *s = OR_IRQ(opaque);
+
+    return s->num_lines >= OLD_MAX_OR_LINES;
+}
+
+static const VMStateDescription vmstate_or_irq_extras = {
+    .name = "or-irq-extras",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .needed = vmstate_extras_needed,
+    .fields = (VMStateField[]) {
+        VMSTATE_VARRAY_UINT16_UNSAFE(levels, qemu_or_irq, num_lines, 0,
+                                     vmstate_info_bool, bool),
+        VMSTATE_END_OF_LIST(),
+    },
+};
+
 static const VMStateDescription vmstate_or_irq = {
     .name = TYPE_OR_IRQ,
     .version_id = 1,
     .minimum_version_id = 1,
     .fields = (VMStateField[]) {
-        VMSTATE_BOOL_ARRAY(levels, qemu_or_irq, MAX_OR_LINES),
+        VMSTATE_BOOL_SUB_ARRAY(levels, qemu_or_irq, 0, OLD_MAX_OR_LINES),
         VMSTATE_END_OF_LIST(),
-    }
+    },
+    .subsections = (const VMStateDescription*[]) {
+        &vmstate_or_irq_extras,
+        NULL
+    },
 };
 
 static Property or_irq_properties[] = {
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [Qemu-devel] [PATCH 24/27] hw/misc/iotkit-secctl.c: Implement SECMPCINTSTATUS
  2018-05-21 14:03 [Qemu-devel] [PATCH 00/27] iommu: support txattrs, support TCG execution, implement TZ MPC Peter Maydell
                   ` (22 preceding siblings ...)
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 23/27] hw/core/or-irq: Support more than 16 inputs to an OR gate Peter Maydell
@ 2018-05-21 14:03 ` Peter Maydell
  2018-05-21 14:04 ` [Qemu-devel] [PATCH 25/27] hw/arm/iotkit: Instantiate MPC Peter Maydell
                   ` (4 subsequent siblings)
  28 siblings, 0 replies; 114+ messages in thread
From: Peter Maydell @ 2018-05-21 14:03 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: patches, Paolo Bonzini, Richard Henderson, Alex Bennée

Implement the SECMPCINTSTATUS register. This is the only register
in the security controller that deals with Memory Protection
Controllers, and it simply provides a read-only view of the
interrupt lines from the various MPCs in the system.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 include/hw/misc/iotkit-secctl.h |  8 +++++++
 hw/misc/iotkit-secctl.c         | 38 +++++++++++++++++++++++++++++++--
 2 files changed, 44 insertions(+), 2 deletions(-)

diff --git a/include/hw/misc/iotkit-secctl.h b/include/hw/misc/iotkit-secctl.h
index faad0c9190..082c14c925 100644
--- a/include/hw/misc/iotkit-secctl.h
+++ b/include/hw/misc/iotkit-secctl.h
@@ -39,6 +39,11 @@
  *  + named GPIO outputs ahb_ppcexp{0,1,2,3}_irq_enable
  *  + named GPIO outputs ahb_ppcexp{0,1,2,3}_irq_clear
  *  + named GPIO inputs ahb_ppcexp{0,1,2,3}_irq_status
+ * Controlling the MPC in the IoTKit:
+ *  + named GPIO input mpc_status
+ * Controlling each of the 16 expansion MPCs which a system using the IoTKit
+ * might provide:
+ *  + named GPIO inputs mpcexp_status[0..15]
  */
 
 #ifndef IOTKIT_SECCTL_H
@@ -55,6 +60,8 @@
 #define IOTS_NUM_APB_PPC 2
 #define IOTS_NUM_APB_EXP_PPC 4
 #define IOTS_NUM_AHB_EXP_PPC 4
+#define IOTS_NUM_EXP_MPC 16
+#define IOTS_NUM_MPC 1
 
 typedef struct IoTKitSecCtl IoTKitSecCtl;
 
@@ -94,6 +101,7 @@ struct IoTKitSecCtl {
     uint32_t secrespcfg;
     uint32_t nsccfg;
     uint32_t brginten;
+    uint32_t mpcintstatus;
 
     IoTKitSecCtlPPC apb[IOTS_NUM_APB_PPC];
     IoTKitSecCtlPPC apbexp[IOTS_NUM_APB_EXP_PPC];
diff --git a/hw/misc/iotkit-secctl.c b/hw/misc/iotkit-secctl.c
index ddd1584d34..de4fd8e36d 100644
--- a/hw/misc/iotkit-secctl.c
+++ b/hw/misc/iotkit-secctl.c
@@ -139,6 +139,9 @@ static MemTxResult iotkit_secctl_s_read(void *opaque, hwaddr addr,
     case A_NSCCFG:
         r = s->nsccfg;
         break;
+    case A_SECMPCINTSTATUS:
+        r = s->mpcintstatus;
+        break;
     case A_SECPPCINTSTAT:
         r = s->secppcintstat;
         break;
@@ -186,7 +189,6 @@ static MemTxResult iotkit_secctl_s_read(void *opaque, hwaddr addr,
     case A_APBSPPPCEXP3:
         r = s->apbexp[offset_to_ppc_idx(offset)].sp;
         break;
-    case A_SECMPCINTSTATUS:
     case A_SECMSCINTSTAT:
     case A_SECMSCINTEN:
     case A_NSMSCEXP:
@@ -572,6 +574,20 @@ static void iotkit_secctl_reset(DeviceState *dev)
     foreach_ppc(s, iotkit_secctl_reset_ppc);
 }
 
+static void iotkit_secctl_mpc_status(void *opaque, int n, int level)
+{
+    IoTKitSecCtl *s = IOTKIT_SECCTL(opaque);
+
+    s->mpcintstatus = deposit32(s->mpcintstatus, 0, 1, !!level);
+}
+
+static void iotkit_secctl_mpcexp_status(void *opaque, int n, int level)
+{
+    IoTKitSecCtl *s = IOTKIT_SECCTL(opaque);
+
+    s->mpcintstatus = deposit32(s->mpcintstatus, n + 16, 1, !!level);
+}
+
 static void iotkit_secctl_ppc_irqstatus(void *opaque, int n, int level)
 {
     IoTKitSecCtlPPC *ppc = opaque;
@@ -640,6 +656,10 @@ static void iotkit_secctl_init(Object *obj)
     qdev_init_gpio_out_named(dev, &s->sec_resp_cfg, "sec_resp_cfg", 1);
     qdev_init_gpio_out_named(dev, &s->nsc_cfg_irq, "nsc_cfg", 1);
 
+    qdev_init_gpio_in_named(dev, iotkit_secctl_mpc_status, "mpc_status", 1);
+    qdev_init_gpio_in_named(dev, iotkit_secctl_mpcexp_status,
+                            "mpcexp_status", IOTS_NUM_EXP_MPC);
+
     memory_region_init_io(&s->s_regs, obj, &iotkit_secctl_s_ops,
                           s, "iotkit-secctl-s-regs", 0x1000);
     memory_region_init_io(&s->ns_regs, obj, &iotkit_secctl_ns_ops,
@@ -660,6 +680,16 @@ static const VMStateDescription iotkit_secctl_ppc_vmstate = {
     }
 };
 
+static const VMStateDescription iotkit_secctl_mpcintstatus_vmstate = {
+    .name = "iotkit-secctl-mpcintstatus",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(mpcintstatus, IoTKitSecCtl),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 static const VMStateDescription iotkit_secctl_vmstate = {
     .name = "iotkit-secctl",
     .version_id = 1,
@@ -677,7 +707,11 @@ static const VMStateDescription iotkit_secctl_vmstate = {
         VMSTATE_STRUCT_ARRAY(ahbexp, IoTKitSecCtl, IOTS_NUM_AHB_EXP_PPC, 1,
                              iotkit_secctl_ppc_vmstate, IoTKitSecCtlPPC),
         VMSTATE_END_OF_LIST()
-    }
+    },
+    .subsections = (const VMStateDescription*[]) {
+        &iotkit_secctl_mpcintstatus_vmstate,
+        NULL
+    },
 };
 
 static void iotkit_secctl_class_init(ObjectClass *klass, void *data)
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [Qemu-devel] [PATCH 25/27] hw/arm/iotkit: Instantiate MPC
  2018-05-21 14:03 [Qemu-devel] [PATCH 00/27] iommu: support txattrs, support TCG execution, implement TZ MPC Peter Maydell
                   ` (23 preceding siblings ...)
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 24/27] hw/misc/iotkit-secctl.c: Implement SECMPCINTSTATUS Peter Maydell
@ 2018-05-21 14:04 ` Peter Maydell
  2018-05-23 11:38   ` Alex Bennée
  2018-05-21 14:04 ` [Qemu-devel] [PATCH 26/27] hw/arm/iotkit: Wire up MPC interrupt lines Peter Maydell
                   ` (3 subsequent siblings)
  28 siblings, 1 reply; 114+ messages in thread
From: Peter Maydell @ 2018-05-21 14:04 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: patches, Paolo Bonzini, Richard Henderson, Alex Bennée

Wire up the one MPC that is part of the IoTKit itself. For the
moment we don't wire up its interrupt line.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 include/hw/arm/iotkit.h |  2 ++
 hw/arm/iotkit.c         | 38 +++++++++++++++++++++++++++-----------
 2 files changed, 29 insertions(+), 11 deletions(-)

diff --git a/include/hw/arm/iotkit.h b/include/hw/arm/iotkit.h
index c6129d926b..b21cf1ab9d 100644
--- a/include/hw/arm/iotkit.h
+++ b/include/hw/arm/iotkit.h
@@ -51,6 +51,7 @@
 #include "hw/arm/armv7m.h"
 #include "hw/misc/iotkit-secctl.h"
 #include "hw/misc/tz-ppc.h"
+#include "hw/misc/tz-mpc.h"
 #include "hw/timer/cmsdk-apb-timer.h"
 #include "hw/misc/unimp.h"
 #include "hw/or-irq.h"
@@ -74,6 +75,7 @@ typedef struct IoTKit {
     IoTKitSecCtl secctl;
     TZPPC apb_ppc0;
     TZPPC apb_ppc1;
+    TZMPC mpc;
     CMSDKAPBTIMER timer0;
     CMSDKAPBTIMER timer1;
     qemu_or_irq ppc_irq_orgate;
diff --git a/hw/arm/iotkit.c b/hw/arm/iotkit.c
index 234185e8f7..160e40c744 100644
--- a/hw/arm/iotkit.c
+++ b/hw/arm/iotkit.c
@@ -130,6 +130,7 @@ static void iotkit_init(Object *obj)
                       TYPE_TZ_PPC);
     init_sysbus_child(obj, "apb-ppc1", &s->apb_ppc1, sizeof(s->apb_ppc1),
                       TYPE_TZ_PPC);
+    init_sysbus_child(obj, "mpc", &s->mpc, sizeof(s->mpc), TYPE_TZ_MPC);
     init_sysbus_child(obj, "timer0", &s->timer0, sizeof(s->timer0),
                       TYPE_CMSDK_APB_TIMER);
     init_sysbus_child(obj, "timer1", &s->timer1, sizeof(s->timer1),
@@ -266,15 +267,6 @@ static void iotkit_realize(DeviceState *dev, Error **errp)
      */
     make_alias(s, &s->alias3, "alias 3", 0x50000000, 0x10000000, 0x40000000);
 
-    /* This RAM should be behind a Memory Protection Controller, but we
-     * don't implement that yet.
-     */
-    memory_region_init_ram(&s->sram0, NULL, "iotkit.sram0", 0x00008000, &err);
-    if (err) {
-        error_propagate(errp, err);
-        return;
-    }
-    memory_region_add_subregion(&s->container, 0x20000000, &s->sram0);
 
     /* Security controller */
     object_property_set_bool(OBJECT(&s->secctl), true, "realized", &err);
@@ -310,6 +302,32 @@ static void iotkit_realize(DeviceState *dev, Error **errp)
     qdev_connect_gpio_out_named(dev_secctl, "sec_resp_cfg", 0,
                                 qdev_get_gpio_in(dev_splitter, 0));
 
+    /* This RAM lives behind the Memory Protection Controller */
+    memory_region_init_ram(&s->sram0, NULL, "iotkit.sram0", 0x00008000, &err);
+    if (err) {
+        error_propagate(errp, err);
+        return;
+    }
+    object_property_set_link(OBJECT(&s->mpc), OBJECT(&s->sram0),
+                             "downstream", &err);
+    if (err) {
+        error_propagate(errp, err);
+        return;
+    }
+    object_property_set_bool(OBJECT(&s->mpc), true, "realized", &err);
+    if (err) {
+        error_propagate(errp, err);
+        return;
+    }
+    /* Map the upstream end of the MPC into the right place... */
+    memory_region_add_subregion(&s->container, 0x20000000,
+                                sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->mpc),
+                                                       1));
+    /* ...and its register interface */
+    memory_region_add_subregion(&s->container, 0x50083000,
+                                sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->mpc),
+                                                       0));
+
     /* Devices behind APB PPC0:
      *   0x40000000: timer0
      *   0x40001000: timer1
@@ -473,8 +491,6 @@ static void iotkit_realize(DeviceState *dev, Error **errp)
     create_unimplemented_device("NS watchdog", 0x40081000, 0x1000);
     create_unimplemented_device("S watchdog", 0x50081000, 0x1000);
 
-    create_unimplemented_device("SRAM0 MPC", 0x50083000, 0x1000);
-
     for (i = 0; i < ARRAY_SIZE(s->ppc_irq_splitter); i++) {
         Object *splitter = OBJECT(&s->ppc_irq_splitter[i]);
 
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [Qemu-devel] [PATCH 26/27] hw/arm/iotkit: Wire up MPC interrupt lines
  2018-05-21 14:03 [Qemu-devel] [PATCH 00/27] iommu: support txattrs, support TCG execution, implement TZ MPC Peter Maydell
                   ` (24 preceding siblings ...)
  2018-05-21 14:04 ` [Qemu-devel] [PATCH 25/27] hw/arm/iotkit: Instantiate MPC Peter Maydell
@ 2018-05-21 14:04 ` Peter Maydell
  2018-05-23 11:39   ` Alex Bennée
  2018-05-21 14:04 ` [Qemu-devel] [PATCH 27/27] hw/arm/mps2-tz.c: Instantiate MPCs Peter Maydell
                   ` (2 subsequent siblings)
  28 siblings, 1 reply; 114+ messages in thread
From: Peter Maydell @ 2018-05-21 14:04 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: patches, Paolo Bonzini, Richard Henderson, Alex Bennée

The interrupt outputs from the MPC in the IoTKit and the expansion
MPCs in the board must be wired up to the security controller, and
also all ORed together to produce a single line to the NVIC.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 include/hw/arm/iotkit.h |  6 ++++
 hw/arm/iotkit.c         | 74 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 80 insertions(+)

diff --git a/include/hw/arm/iotkit.h b/include/hw/arm/iotkit.h
index b21cf1ab9d..2cddde55dd 100644
--- a/include/hw/arm/iotkit.h
+++ b/include/hw/arm/iotkit.h
@@ -42,6 +42,9 @@
  *  + named GPIO outputs ahb_ppcexp{0,1,2,3}_irq_enable
  *  + named GPIO outputs ahb_ppcexp{0,1,2,3}_irq_clear
  *  + named GPIO inputs ahb_ppcexp{0,1,2,3}_irq_status
+ * Controlling each of the 16 expansion MPCs which a system using the IoTKit
+ * might provide:
+ *  + named GPIO inputs mpcexp_status[0..15]
  */
 
 #ifndef IOTKIT_H
@@ -81,6 +84,8 @@ typedef struct IoTKit {
     qemu_or_irq ppc_irq_orgate;
     SplitIRQ sec_resp_splitter;
     SplitIRQ ppc_irq_splitter[NUM_PPCS];
+    SplitIRQ mpc_irq_splitter[IOTS_NUM_EXP_MPC + IOTS_NUM_MPC];
+    qemu_or_irq mpc_irq_orgate;
 
     UnimplementedDeviceState dualtimer;
     UnimplementedDeviceState s32ktimer;
@@ -99,6 +104,7 @@ typedef struct IoTKit {
     qemu_irq nsc_cfg_in;
 
     qemu_irq irq_status_in[NUM_EXTERNAL_PPCS];
+    qemu_irq mpcexp_status_in[IOTS_NUM_EXP_MPC];
 
     uint32_t nsccfg;
 
diff --git a/hw/arm/iotkit.c b/hw/arm/iotkit.c
index 160e40c744..133d5bb34f 100644
--- a/hw/arm/iotkit.c
+++ b/hw/arm/iotkit.c
@@ -131,6 +131,18 @@ static void iotkit_init(Object *obj)
     init_sysbus_child(obj, "apb-ppc1", &s->apb_ppc1, sizeof(s->apb_ppc1),
                       TYPE_TZ_PPC);
     init_sysbus_child(obj, "mpc", &s->mpc, sizeof(s->mpc), TYPE_TZ_MPC);
+    object_initialize(&s->mpc_irq_orgate, sizeof(s->mpc_irq_orgate),
+                      TYPE_OR_IRQ);
+    object_property_add_child(obj, "mpc-irq-orgate",
+                              OBJECT(&s->mpc_irq_orgate), &error_abort);
+    for (i = 0; i < ARRAY_SIZE(s->mpc_irq_splitter); i++) {
+        char *name = g_strdup_printf("mpc-irq-splitter-%d", i);
+        SplitIRQ *splitter = &s->mpc_irq_splitter[i];
+
+        object_initialize(splitter, sizeof(*splitter), TYPE_SPLIT_IRQ);
+        object_property_add_child(obj, name, OBJECT(splitter), &error_abort);
+        g_free(name);
+    }
     init_sysbus_child(obj, "timer0", &s->timer0, sizeof(s->timer0),
                       TYPE_CMSDK_APB_TIMER);
     init_sysbus_child(obj, "timer1", &s->timer1, sizeof(s->timer1),
@@ -163,6 +175,12 @@ static void iotkit_exp_irq(void *opaque, int n, int level)
     qemu_set_irq(s->exp_irqs[n], level);
 }
 
+static void iotkit_mpcexp_status(void *opaque, int n, int level)
+{
+    IoTKit *s = IOTKIT(opaque);
+    qemu_set_irq(s->mpcexp_status_in[n], level);
+}
+
 static void iotkit_realize(DeviceState *dev, Error **errp)
 {
     IoTKit *s = IOTKIT(dev);
@@ -328,6 +346,22 @@ static void iotkit_realize(DeviceState *dev, Error **errp)
                                 sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->mpc),
                                                        0));
 
+    /* We must OR together lines from the MPC splitters to go to the NVIC */
+    object_property_set_int(OBJECT(&s->mpc_irq_orgate),
+                            IOTS_NUM_EXP_MPC + IOTS_NUM_MPC, "num-lines", &err);
+    if (err) {
+        error_propagate(errp, err);
+        return;
+    }
+    object_property_set_bool(OBJECT(&s->mpc_irq_orgate), true,
+                             "realized", &err);
+    if (err) {
+        error_propagate(errp, err);
+        return;
+    }
+    qdev_connect_gpio_out(DEVICE(&s->mpc_irq_orgate), 0,
+                          qdev_get_gpio_in(DEVICE(&s->armv7m), 9));
+
     /* Devices behind APB PPC0:
      *   0x40000000: timer0
      *   0x40001000: timer1
@@ -536,6 +570,46 @@ static void iotkit_realize(DeviceState *dev, Error **errp)
         g_free(gpioname);
     }
 
+    /* Wire up the splitters for the MPC IRQs */
+    for (i = 0; i < IOTS_NUM_EXP_MPC + IOTS_NUM_MPC; i++) {
+        SplitIRQ *splitter = &s->mpc_irq_splitter[i];
+        DeviceState *dev_splitter = DEVICE(splitter);
+
+        object_property_set_int(OBJECT(splitter), 2, "num-lines", &err);
+        if (err) {
+            error_propagate(errp, err);
+            return;
+        }
+        object_property_set_bool(OBJECT(splitter), true, "realized", &err);
+        if (err) {
+            error_propagate(errp, err);
+            return;
+        }
+
+        if (i < IOTS_NUM_EXP_MPC) {
+            /* Splitter input is from GPIO input line */
+            s->mpcexp_status_in[i] = qdev_get_gpio_in(dev_splitter, 0);
+            qdev_connect_gpio_out(dev_splitter, 0,
+                                  qdev_get_gpio_in_named(dev_secctl,
+                                                         "mpcexp_status", i));
+        } else {
+            /* Splitter input is from our own MPC */
+            qdev_connect_gpio_out_named(DEVICE(&s->mpc), "irq", 0,
+                                        qdev_get_gpio_in(dev_splitter, 0));
+            qdev_connect_gpio_out(dev_splitter, 0,
+                                  qdev_get_gpio_in_named(dev_secctl,
+                                                         "mpc_status", 0));
+        }
+
+        qdev_connect_gpio_out(dev_splitter, 1,
+                              qdev_get_gpio_in(DEVICE(&s->mpc_irq_orgate), i));
+    }
+    /* Create GPIO inputs which will pass the line state for our
+     * mpcexp_irq inputs to the correct splitter devices.
+     */
+    qdev_init_gpio_in_named(dev, iotkit_mpcexp_status, "mpcexp_status",
+                            IOTS_NUM_EXP_MPC);
+
     iotkit_forward_sec_resp_cfg(s);
 
     system_clock_scale = NANOSECONDS_PER_SECOND / s->mainclk_frq;
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [Qemu-devel] [PATCH 27/27] hw/arm/mps2-tz.c: Instantiate MPCs
  2018-05-21 14:03 [Qemu-devel] [PATCH 00/27] iommu: support txattrs, support TCG execution, implement TZ MPC Peter Maydell
                   ` (25 preceding siblings ...)
  2018-05-21 14:04 ` [Qemu-devel] [PATCH 26/27] hw/arm/iotkit: Wire up MPC interrupt lines Peter Maydell
@ 2018-05-21 14:04 ` Peter Maydell
  2018-05-23 11:41   ` Alex Bennée
  2018-05-21 15:10 ` [Qemu-devel] [PATCH 00/27] iommu: support txattrs, support TCG execution, implement TZ MPC no-reply
  2018-05-30 16:58 ` Paolo Bonzini
  28 siblings, 1 reply; 114+ messages in thread
From: Peter Maydell @ 2018-05-21 14:04 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: patches, Paolo Bonzini, Richard Henderson, Alex Bennée

Instantiate and wire up the Memory Protection Controllers
in the MPS2 board itself.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/arm/mps2-tz.c | 71 ++++++++++++++++++++++++++++++------------------
 1 file changed, 44 insertions(+), 27 deletions(-)

diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c
index 8dc8bfd4ab..a58b5dea79 100644
--- a/hw/arm/mps2-tz.c
+++ b/hw/arm/mps2-tz.c
@@ -44,6 +44,7 @@
 #include "hw/timer/cmsdk-apb-timer.h"
 #include "hw/misc/mps2-scc.h"
 #include "hw/misc/mps2-fpgaio.h"
+#include "hw/misc/tz-mpc.h"
 #include "hw/arm/iotkit.h"
 #include "hw/devices.h"
 #include "net/net.h"
@@ -64,13 +65,12 @@ typedef struct {
 
     IoTKit iotkit;
     MemoryRegion psram;
-    MemoryRegion ssram1;
+    MemoryRegion ssram[3];
     MemoryRegion ssram1_m;
-    MemoryRegion ssram23;
     MPS2SCC scc;
     MPS2FPGAIO fpgaio;
     TZPPC ppc[5];
-    UnimplementedDeviceState ssram_mpc[3];
+    TZMPC ssram_mpc[3];
     UnimplementedDeviceState spi[5];
     UnimplementedDeviceState i2c[4];
     UnimplementedDeviceState i2s_audio;
@@ -95,16 +95,6 @@ typedef struct {
 /* Main SYSCLK frequency in Hz */
 #define SYSCLK_FRQ 20000000
 
-/* Initialize the auxiliary RAM region @mr and map it into
- * the memory map at @base.
- */
-static void make_ram(MemoryRegion *mr, const char *name,
-                     hwaddr base, hwaddr size)
-{
-    memory_region_init_ram(mr, NULL, name, size, &error_fatal);
-    memory_region_add_subregion(get_system_memory(), base, mr);
-}
-
 /* Create an alias of an entire original MemoryRegion @orig
  * located at @base in the memory map.
  */
@@ -224,6 +214,44 @@ static MemoryRegion *make_fpgaio(MPS2TZMachineState *mms, void *opaque,
     return sysbus_mmio_get_region(SYS_BUS_DEVICE(fpgaio), 0);
 }
 
+static MemoryRegion *make_mpc(MPS2TZMachineState *mms, void *opaque,
+                              const char *name, hwaddr size)
+{
+    TZMPC *mpc = opaque;
+    int i = mpc - &mms->ssram_mpc[0];
+    MemoryRegion *ssram = &mms->ssram[i];
+    MemoryRegion *upstream;
+    char *mpcname = g_strdup_printf("%s-mpc", name);
+    static uint32_t ramsize[] = { 0x00400000, 0x00200000, 0x00200000 };
+    static uint32_t rambase[] = { 0x00000000, 0x28000000, 0x28200000 };
+
+    memory_region_init_ram(ssram, NULL, name, ramsize[i], &error_fatal);
+
+    init_sysbus_child(OBJECT(mms), mpcname, mpc,
+                      sizeof(mms->ssram_mpc[0]), TYPE_TZ_MPC);
+    object_property_set_link(OBJECT(mpc), OBJECT(ssram),
+                             "downstream", &error_fatal);
+    object_property_set_bool(OBJECT(mpc), true, "realized", &error_fatal);
+    /* Map the upstream end of the MPC into system memory */
+    upstream = sysbus_mmio_get_region(SYS_BUS_DEVICE(mpc), 1);
+    memory_region_add_subregion(get_system_memory(), rambase[i], upstream);
+    /* and connect its interrupt to the IoTKit */
+    qdev_connect_gpio_out_named(DEVICE(mpc), "irq", 0,
+                                qdev_get_gpio_in_named(DEVICE(&mms->iotkit),
+                                                       "mpcexp_status", i));
+
+    /* The first SSRAM is a special case as it has an alias; accesses to
+     * the alias region at 0x00400000 must also go to the MPC upstream.
+     */
+    if (i == 0) {
+        make_ram_alias(&mms->ssram1_m, "mps.ssram1_m", upstream, 0x00400000);
+    }
+
+    g_free(mpcname);
+    /* Return the register interface MR for our caller to map behind the PPC */
+    return sysbus_mmio_get_region(SYS_BUS_DEVICE(mpc), 0);
+}
+
 static void mps2tz_common_init(MachineState *machine)
 {
     MPS2TZMachineState *mms = MPS2TZ_MACHINE(machine);
@@ -285,14 +313,6 @@ static void mps2tz_common_init(MachineState *machine)
                                          NULL, "mps.ram", 0x01000000);
     memory_region_add_subregion(system_memory, 0x80000000, &mms->psram);
 
-    /* The SSRAM memories should all be behind Memory Protection Controllers,
-     * but we don't implement that yet.
-     */
-    make_ram(&mms->ssram1, "mps.ssram1", 0x00000000, 0x00400000);
-    make_ram_alias(&mms->ssram1_m, "mps.ssram1_m", &mms->ssram1, 0x00400000);
-
-    make_ram(&mms->ssram23, "mps.ssram23", 0x28000000, 0x00400000);
-
     /* The overflow IRQs for all UARTs are ORed together.
      * Tx, Rx and "combined" IRQs are sent to the NVIC separately.
      * Create the OR gate for this.
@@ -322,12 +342,9 @@ static void mps2tz_common_init(MachineState *machine)
     const PPCInfo ppcs[] = { {
             .name = "apb_ppcexp0",
             .ports = {
-                { "ssram-mpc0", make_unimp_dev, &mms->ssram_mpc[0],
-                  0x58007000, 0x1000 },
-                { "ssram-mpc1", make_unimp_dev, &mms->ssram_mpc[1],
-                  0x58008000, 0x1000 },
-                { "ssram-mpc2", make_unimp_dev, &mms->ssram_mpc[2],
-                  0x58009000, 0x1000 },
+                { "ssram-0", make_mpc, &mms->ssram_mpc[0], 0x58007000, 0x1000 },
+                { "ssram-1", make_mpc, &mms->ssram_mpc[1], 0x58008000, 0x1000 },
+                { "ssram-2", make_mpc, &mms->ssram_mpc[2], 0x58009000, 0x1000 },
             },
         }, {
             .name = "apb_ppcexp1",
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 23/27] hw/core/or-irq: Support more than 16 inputs to an OR gate
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 23/27] hw/core/or-irq: Support more than 16 inputs to an OR gate Peter Maydell
@ 2018-05-21 14:34   ` Paolo Bonzini
  2018-05-21 15:02     ` Peter Maydell
  0 siblings, 1 reply; 114+ messages in thread
From: Paolo Bonzini @ 2018-05-21 14:34 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel
  Cc: patches, Richard Henderson, Alex Bennée

On 21/05/2018 16:03, Peter Maydell wrote:
> + * VMState array; devices with more inputs than this need to
> + * migrate the extra lines via a subsection.
> + * The subsection migrates as much of the levels[] array as is needed
> + * (including repeating the first 16 elements), to avoid the awkwardness
> + * of splitting it in two to meet the requirements of VMSTATE_VARRAY_UINT16.
> + */
> +#define OLD_MAX_OR_LINES 16
> +#if MAX_OR_LINES < OLD_MAX_OR_LINES
> +#error MAX_OR_LINES must be at least 16 for migration compatibility
> +#endif
> +
> +static bool vmstate_extras_needed(void *opaque)
> +{
> +    qemu_or_irq *s = OR_IRQ(opaque);
> +
> +    return s->num_lines >= OLD_MAX_OR_LINES;
> +}
> +
> +static const VMStateDescription vmstate_or_irq_extras = {
> +    .name = "or-irq-extras",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .needed = vmstate_extras_needed,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_VARRAY_UINT16_UNSAFE(levels, qemu_or_irq, num_lines, 0,
> +                                     vmstate_info_bool, bool),
> +        VMSTATE_END_OF_LIST(),
> +    },
> +};
> +


Why do the levels have to be migrated at all?  It should be enough if
the IRQ level is either migrated manually, or restored (e.g. in
post_save callbacks) through other data that is migrated.

Paolo

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 23/27] hw/core/or-irq: Support more than 16 inputs to an OR gate
  2018-05-21 14:34   ` Paolo Bonzini
@ 2018-05-21 15:02     ` Peter Maydell
  2018-05-30 16:59       ` Paolo Bonzini
  0 siblings, 1 reply; 114+ messages in thread
From: Peter Maydell @ 2018-05-21 15:02 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: qemu-arm, QEMU Developers, patches, Richard Henderson, Alex Bennée

On 21 May 2018 at 15:34, Paolo Bonzini <pbonzini@redhat.com> wrote:
> Why do the levels have to be migrated at all?  It should be enough if
> the IRQ level is either migrated manually, or restored (e.g. in
> post_save callbacks) through other data that is migrated.

This is standard behaviour for devices: they track their
inbound irq/gpio lines, and then that becomes internal state for
them that must be migrated.

If we didn't migrate the input line state, then after a migration
the levels[] array would be all zeroes, and the next time a
connected device signalled a high-to-low transition we'd take
the output line low even if it should not be (because we'd have
forgotten that some other input lines were high).

In a different world, the state would be in the qemu_irq line itself
(in the same way that in hardware signal lines are their own state),
but we can't get there from here.

thanks
-- PMM

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 00/27] iommu: support txattrs, support TCG execution, implement TZ MPC
  2018-05-21 14:03 [Qemu-devel] [PATCH 00/27] iommu: support txattrs, support TCG execution, implement TZ MPC Peter Maydell
                   ` (26 preceding siblings ...)
  2018-05-21 14:04 ` [Qemu-devel] [PATCH 27/27] hw/arm/mps2-tz.c: Instantiate MPCs Peter Maydell
@ 2018-05-21 15:10 ` no-reply
  2018-05-30 16:58 ` Paolo Bonzini
  28 siblings, 0 replies; 114+ messages in thread
From: no-reply @ 2018-05-21 15:10 UTC (permalink / raw)
  To: peter.maydell
  Cc: famz, qemu-arm, qemu-devel, pbonzini, rth, alex.bennee, patches

Hi,

This series seems to have some coding style problems. See output below for
more information:

Type: series
Message-id: 20180521140402.23318-1-peter.maydell@linaro.org
Subject: [Qemu-devel] [PATCH 00/27] iommu: support txattrs, support TCG execution, implement TZ MPC

=== TEST SCRIPT BEGIN ===
#!/bin/bash

BASE=base
n=1
total=$(git log --oneline $BASE.. | wc -l)
failed=0

git config --local diff.renamelimit 0
git config --local diff.renames True
git config --local diff.algorithm histogram

commits="$(git log --format=%H --reverse $BASE..)"
for c in $commits; do
    echo "Checking PATCH $n/$total: $(git log -n 1 --format=%s $c)..."
    if ! git show $c --format=email | ./scripts/checkpatch.pl --mailback -; then
        failed=1
        echo
    fi
    n=$((n+1))
done

exit $failed
=== TEST SCRIPT END ===

Updating 3c8cf5a9c21ff8782164d1def7f44bd888713384
From https://github.com/patchew-project/qemu
   5bcf917ee3..9802316ed6  master     -> master
 t [tag update]            patchew/20180509034658.26455-1-f4bug@amsat.org -> patchew/20180509034658.26455-1-f4bug@amsat.org
 * [new tag]               patchew/20180521140402.23318-1-peter.maydell@linaro.org -> patchew/20180521140402.23318-1-peter.maydell@linaro.org
Switched to a new branch 'test'
19069d042c hw/arm/mps2-tz.c: Instantiate MPCs
545f7d3702 hw/arm/iotkit: Wire up MPC interrupt lines
965dcdf3c3 hw/arm/iotkit: Instantiate MPC
5aeb41635d hw/misc/iotkit-secctl.c: Implement SECMPCINTSTATUS
06b812c890 hw/core/or-irq: Support more than 16 inputs to an OR gate
d29f89b59f vmstate.h: Provide VMSTATE_BOOL_SUB_ARRAY
417b50c6f7 hw/misc/tz_mpc.c: Honour the BLK_LUT settings in translate
4d9bb0adb6 hw/misc/tz-mpc.c: Implement correct blocked-access behaviour
8b1bbc0790 hw/misc/tz-mpc.c: Implement registers
66fad85c8d hw/misc/tz-mpc.c: Implement the Arm TrustZone Memory Protection Controller
1e200a4e8f exec.c: Handle IOMMUs in address_space_translate_for_iotlb()
1b9a2ae51d iommu: Add IOMMU index argument to translate method
b022117fca iommu: Add IOMMU index argument to notifier APIs
71890073bb iommu: Add IOMMU index concept to IOMMU API
0093540ad1 Make address_space_translate_iommu take a MemTxAttrs argument
09947170a9 Make flatview_do_translate() take a MemTxAttrs argument
8388c25d74 Make address_space_get_iotlb_entry() take a MemTxAttrs argument
4f8f7862e7 Make flatview_translate() take a MemTxAttrs argument
29b8404366 Make flatview_access_valid() take a MemTxAttrs argument
2779af384f Make MemoryRegion valid.accepts callback take a MemTxAttrs argument
7ec3d4eee3 Make memory_region_access_valid() take a MemTxAttrs argument
2dbbe355a7 Make flatview_extend_translation() take a MemTxAttrs argument
b1a96a2a28 Make address_space_access_valid() take a MemTxAttrs argument
07fc6cedd7 Make address_space_map() take a MemTxAttrs argument
b99085d422 Make address_space_translate{, _cached}() take a MemTxAttrs argument
a8e73cc870 Make tb_invalidate_phys_addr() take a MemTxAttrs argument
c6d0746766 memory.h: Improve IOMMU related documentation

=== OUTPUT BEGIN ===
Checking PATCH 1/27: memory.h: Improve IOMMU related documentation...
Checking PATCH 2/27: Make tb_invalidate_phys_addr() take a MemTxAttrs argument...
Checking PATCH 3/27: Make address_space_translate{, _cached}() take a MemTxAttrs argument...
Checking PATCH 4/27: Make address_space_map() take a MemTxAttrs argument...
Checking PATCH 5/27: Make address_space_access_valid() take a MemTxAttrs argument...
Checking PATCH 6/27: Make flatview_extend_translation() take a MemTxAttrs argument...
Checking PATCH 7/27: Make memory_region_access_valid() take a MemTxAttrs argument...
Checking PATCH 8/27: Make MemoryRegion valid.accepts callback take a MemTxAttrs argument...
Checking PATCH 9/27: Make flatview_access_valid() take a MemTxAttrs argument...
Checking PATCH 10/27: Make flatview_translate() take a MemTxAttrs argument...
Checking PATCH 11/27: Make address_space_get_iotlb_entry() take a MemTxAttrs argument...
Checking PATCH 12/27: Make flatview_do_translate() take a MemTxAttrs argument...
Checking PATCH 13/27: Make address_space_translate_iommu take a MemTxAttrs argument...
WARNING: line over 80 characters
#30: FILE: exec.c:492:
+                                                         AddressSpace **target_as,

total: 0 errors, 1 warnings, 32 lines checked

Your patch has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
Checking PATCH 14/27: iommu: Add IOMMU index concept to IOMMU API...
Checking PATCH 15/27: iommu: Add IOMMU index argument to notifier APIs...
Checking PATCH 16/27: iommu: Add IOMMU index argument to translate method...
Checking PATCH 17/27: exec.c: Handle IOMMUs in address_space_translate_for_iotlb()...
Checking PATCH 18/27: hw/misc/tz-mpc.c: Implement the Arm TrustZone Memory Protection Controller...
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#81: 
new file mode 100644

total: 0 errors, 1 warnings, 486 lines checked

Your patch has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
Checking PATCH 19/27: hw/misc/tz-mpc.c: Implement registers...
Checking PATCH 20/27: hw/misc/tz-mpc.c: Implement correct blocked-access behaviour...
Checking PATCH 21/27: hw/misc/tz_mpc.c: Honour the BLK_LUT settings in translate...
Checking PATCH 22/27: vmstate.h: Provide VMSTATE_BOOL_SUB_ARRAY...
Checking PATCH 23/27: hw/core/or-irq: Support more than 16 inputs to an OR gate...
ERROR: spaces required around that '*' (ctx:VxV)
#71: FILE: hw/core/or-irq.c:108:
+    .subsections = (const VMStateDescription*[]) {
                                             ^

total: 1 errors, 0 warnings, 62 lines checked

Your patch has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.

Checking PATCH 24/27: hw/misc/iotkit-secctl.c: Implement SECMPCINTSTATUS...
ERROR: spaces required around that '*' (ctx:VxV)
#92: FILE: hw/misc/iotkit-secctl.c:711:
+    .subsections = (const VMStateDescription*[]) {
                                             ^

total: 1 errors, 0 warnings, 100 lines checked

Your patch has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.

Checking PATCH 25/27: hw/arm/iotkit: Instantiate MPC...
Checking PATCH 26/27: hw/arm/iotkit: Wire up MPC interrupt lines...
Checking PATCH 27/27: hw/arm/mps2-tz.c: Instantiate MPCs...
=== OUTPUT END ===

Test command exited with code: 1


---
Email generated automatically by Patchew [http://patchew.org/].
Please send your feedback to patchew-devel@redhat.com

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 01/27] memory.h: Improve IOMMU related documentation
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 01/27] memory.h: Improve IOMMU related documentation Peter Maydell
@ 2018-05-21 19:46   ` Richard Henderson
  2018-05-22  9:16   ` Alex Bennée
  2018-05-22 11:40   ` Auger Eric
  2 siblings, 0 replies; 114+ messages in thread
From: Richard Henderson @ 2018-05-21 19:46 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel
  Cc: patches, Paolo Bonzini, Alex Bennée

On 05/21/2018 07:03 AM, Peter Maydell wrote:
> Add more detail to the documentation for memory_region_init_iommu()
> and other IOMMU-related functions and data structures.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
> v2->v3 changes:
>  * minor wording tweaks per Eric's review
>  * moved the bit about requirements to notify out from the translate
>    method docs to the top level class doc comment
>  * added description of flags argument and in particular that it's
>    just an optimization and callers can pass IOMMU_NONE to get the
>    full permissions
> v1 -> v2 changes:
>  * documented replay method
>  * added note about wanting RCU or big qemu lock while calling
>    translate
> ---
>  include/exec/memory.h | 105 ++++++++++++++++++++++++++++++++++++++----
>  1 file changed, 95 insertions(+), 10 deletions(-)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 02/27] Make tb_invalidate_phys_addr() take a MemTxAttrs argument
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 02/27] Make tb_invalidate_phys_addr() take a MemTxAttrs argument Peter Maydell
@ 2018-05-21 23:54   ` Richard Henderson
  2018-05-22  9:21   ` Alex Bennée
  1 sibling, 0 replies; 114+ messages in thread
From: Richard Henderson @ 2018-05-21 23:54 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel
  Cc: patches, Paolo Bonzini, Alex Bennée

On 05/21/2018 07:03 AM, Peter Maydell wrote:
> As part of plumbing MemTxAttrs down to the IOMMU translate method,
> add MemTxAttrs as an argument to tb_invalidate_phys_addr().
> Its callers either have an attrs value to hand, or don't care
> and can use MEMTXATTRS_UNSPECIFIED.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 14/27] iommu: Add IOMMU index concept to IOMMU API
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 14/27] iommu: Add IOMMU index concept to IOMMU API Peter Maydell
@ 2018-05-22  3:03   ` Peter Xu
  2018-05-22  8:40     ` Peter Maydell
  2018-05-22 12:58   ` Auger Eric
  2018-05-22 17:42   ` Richard Henderson
  2 siblings, 1 reply; 114+ messages in thread
From: Peter Xu @ 2018-05-22  3:03 UTC (permalink / raw)
  To: Peter Maydell
  Cc: qemu-arm, qemu-devel, Paolo Bonzini, Richard Henderson,
	Alex Bennée, patches

On Mon, May 21, 2018 at 03:03:49PM +0100, Peter Maydell wrote:
> If an IOMMU supports mappings that care about the memory
> transaction attributes, then it no longer has a unique
> address -> output mapping, but more than one. We can
> represent these using an IOMMU index, analogous to TCG's
> mmu indexes.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  include/exec/memory.h | 52 +++++++++++++++++++++++++++++++++++++++++++
>  memory.c              | 23 +++++++++++++++++++
>  2 files changed, 75 insertions(+)
> 
> diff --git a/include/exec/memory.h b/include/exec/memory.h
> index 309fdfb89b..f6226fb263 100644
> --- a/include/exec/memory.h
> +++ b/include/exec/memory.h
> @@ -206,6 +206,20 @@ enum IOMMUMemoryRegionAttr {
>   * to report whenever mappings are changed, by calling
>   * memory_region_notify_iommu() (or, if necessary, by calling
>   * memory_region_notify_one() for each registered notifier).
> + *
> + * Conceptually an IOMMU provides a mapping from input address
> + * to an output TLB entry. If the IOMMU is aware of memory transaction
> + * attributes and the output TLB entry depends on the transaction
> + * attributes, we represent this using IOMMU indexes. Each index

Hi, Peter,

In what case will an IOMMU translation depend on translation
attributes?  It seems to me that we should always pass in the
translation attributes into the translate() function.  The translate()
function can omit that parameter if the specific IOMMU does not need
that information, but still I am confused about why we need to index
IOMMU by translation attributes.

> + * selects a particular translation table that the IOMMU has:
> + *   @attrs_to_index returns the IOMMU index for a set of transaction attributes
> + *   @translate takes an input address and an IOMMU index
> + * and the mapping returned can only depend on the input address and the
> + * IOMMU index.
> + *
> + * Most IOMMUs don't care about the transaction attributes and support
> + * only a single IOMMU index. A more complex IOMMU might have one index
> + * for secure transactions and one for non-secure transactions.
>   */
>  typedef struct IOMMUMemoryRegionClass {
>      /* private */
> @@ -290,6 +304,26 @@ typedef struct IOMMUMemoryRegionClass {
>       */
>      int (*get_attr)(IOMMUMemoryRegion *iommu, enum IOMMUMemoryRegionAttr attr,
>                      void *data);
> +
> +    /* Return the IOMMU index to use for a given set of transaction attributes.
> +     *
> +     * Optional method: if an IOMMU only supports a single IOMMU index then
> +     * the default implementation of memory_region_iommu_attrs_to_index()
> +     * will return 0.
> +     *
> +     * The indexes supported by an IOMMU must be contiguous, starting at 0.
> +     *
> +     * @iommu: the IOMMUMemoryRegion
> +     * @attrs: memory transaction attributes
> +     */
> +    int (*attrs_to_index)(IOMMUMemoryRegion *iommu, MemTxAttrs attrs);
> +
> +    /* Return the number of IOMMU indexes this IOMMU supports.
> +     *
> +     * Optional method: if this method is not provided, then
> +     * memory_region_iommu_num_indexes() will return 1, indicating that
> +     * only a single IOMMU index is supported.
> +     */

The num_indexes() definition is missing, and I saw that in the next
patch.  We'll possibly want to move it here.

Regards,

-- 
Peter Xu

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 14/27] iommu: Add IOMMU index concept to IOMMU API
  2018-05-22  3:03   ` Peter Xu
@ 2018-05-22  8:40     ` Peter Maydell
  2018-05-22 11:02       ` Peter Xu
  0 siblings, 1 reply; 114+ messages in thread
From: Peter Maydell @ 2018-05-22  8:40 UTC (permalink / raw)
  To: Peter Xu
  Cc: qemu-arm, QEMU Developers, Paolo Bonzini, Richard Henderson,
	Alex Bennée, patches

On 22 May 2018 at 04:03, Peter Xu <peterx@redhat.com> wrote:
> On Mon, May 21, 2018 at 03:03:49PM +0100, Peter Maydell wrote:
>> If an IOMMU supports mappings that care about the memory
>> transaction attributes, then it no longer has a unique
>> address -> output mapping, but more than one. We can
>> represent these using an IOMMU index, analogous to TCG's
>> mmu indexes.
>>
>> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
>> ---
>>  include/exec/memory.h | 52 +++++++++++++++++++++++++++++++++++++++++++
>>  memory.c              | 23 +++++++++++++++++++
>>  2 files changed, 75 insertions(+)
>>
>> diff --git a/include/exec/memory.h b/include/exec/memory.h
>> index 309fdfb89b..f6226fb263 100644
>> --- a/include/exec/memory.h
>> +++ b/include/exec/memory.h
>> @@ -206,6 +206,20 @@ enum IOMMUMemoryRegionAttr {
>>   * to report whenever mappings are changed, by calling
>>   * memory_region_notify_iommu() (or, if necessary, by calling
>>   * memory_region_notify_one() for each registered notifier).
>> + *
>> + * Conceptually an IOMMU provides a mapping from input address
>> + * to an output TLB entry. If the IOMMU is aware of memory transaction
>> + * attributes and the output TLB entry depends on the transaction
>> + * attributes, we represent this using IOMMU indexes. Each index
>
> Hi, Peter,
>
> In what case will an IOMMU translation depend on translation
> attributes?  It seems to me that we should always pass in the
> translation attributes into the translate() function.  The translate()
> function can omit that parameter if the specific IOMMU does not need
> that information, but still I am confused about why we need to index
> IOMMU by translation attributes.

The MPC implementation at the tail end of the patchset is
one example -- it needs to look at attrs.secure, because
"translation for secure access to address X" differs from
that for address Y". The Arm SMMUv3 is the same when it supports
TrustZone (the implementation in-tree does not), and it can also
give different permissions for transactions with attrs.user = 0 vs 1.

The reason for not just passing in the transaction attributes to
translate is that
(a) the iommu index abstraction makes the notifier setup simpler:
rather than having to have some indication in the API of which
of the transaction attributes are important and which the notifier
cares about, we can just use indexs
(b) it means that it's harder to write an iommu with the bug that
it looks at parts of the transaction attributes that it didn't
claim were important in the notifier API

> The num_indexes() definition is missing, and I saw that in the next
> patch.  We'll possibly want to move it here.

Huh. I ran into that and thought I'd fixed it in my local tree -- I must have
failed to actually move the change to the right patch. Sorry about that.

thanks
-- PMM

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 01/27] memory.h: Improve IOMMU related documentation
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 01/27] memory.h: Improve IOMMU related documentation Peter Maydell
  2018-05-21 19:46   ` Richard Henderson
@ 2018-05-22  9:16   ` Alex Bennée
  2018-05-22 11:40   ` Auger Eric
  2 siblings, 0 replies; 114+ messages in thread
From: Alex Bennée @ 2018-05-22  9:16 UTC (permalink / raw)
  To: Peter Maydell
  Cc: qemu-arm, qemu-devel, patches, Paolo Bonzini, Richard Henderson


Peter Maydell <peter.maydell@linaro.org> writes:

> Add more detail to the documentation for memory_region_init_iommu()
> and other IOMMU-related functions and data structures.
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

> ---
> v2->v3 changes:
>  * minor wording tweaks per Eric's review
>  * moved the bit about requirements to notify out from the translate
>    method docs to the top level class doc comment
>  * added description of flags argument and in particular that it's
>    just an optimization and callers can pass IOMMU_NONE to get the
>    full permissions
> v1 -> v2 changes:
>  * documented replay method
>  * added note about wanting RCU or big qemu lock while calling
>    translate
> ---
>  include/exec/memory.h | 105 ++++++++++++++++++++++++++++++++++++++----
>  1 file changed, 95 insertions(+), 10 deletions(-)
>
> diff --git a/include/exec/memory.h b/include/exec/memory.h
> index 4fa1227f13..cce355d2d8 100644
> --- a/include/exec/memory.h
> +++ b/include/exec/memory.h
> @@ -194,29 +194,100 @@ enum IOMMUMemoryRegionAttr {
>      IOMMU_ATTR_SPAPR_TCE_FD
>  };
>
> +/**
> + * IOMMUMemoryRegionClass:
> + *
> + * All IOMMU implementations need to subclass TYPE_IOMMU_MEMORY_REGION
> + * and provide an implementation of at least the @translate method here
> + * to handle requests to the memory region. Other methods are optional.
> + *
> + * The IOMMU implementation must use the IOMMU notifier infrastructure
> + * to report whenever mappings are changed, by calling
> + * memory_region_notify_iommu() (or, if necessary, by calling
> + * memory_region_notify_one() for each registered notifier).
> + */
>  typedef struct IOMMUMemoryRegionClass {
>      /* private */
>      struct DeviceClass parent_class;
>
>      /*
> -     * Return a TLB entry that contains a given address. Flag should
> -     * be the access permission of this translation operation. We can
> -     * set flag to IOMMU_NONE to mean that we don't need any
> -     * read/write permission checks, like, when for region replay.
> +     * Return a TLB entry that contains a given address.
> +     *
> +     * The IOMMUAccessFlags indicated via @flag are optional and may
> +     * be specified as IOMMU_NONE to indicate that the caller needs
> +     * the full translation information for both reads and writes. If
> +     * the access flags are specified then the IOMMU implementation
> +     * may use this as an optimization, to stop doing a page table
> +     * walk as soon as it knows that the requested permissions are not
> +     * allowed. If IOMMU_NONE is passed then the IOMMU must do the
> +     * full page table walk and report the permissions in the returned
> +     * IOMMUTLBEntry. (Note that this implies that an IOMMU may not
> +     * return different mappings for reads and writes.)
> +     *
> +     * The returned information remains valid while the caller is
> +     * holding the big QEMU lock or is inside an RCU critical section;
> +     * if the caller wishes to cache the mapping beyond that it must
> +     * register an IOMMU notifier so it can invalidate its cached
> +     * information when the IOMMU mapping changes.
> +     *
> +     * @iommu: the IOMMUMemoryRegion
> +     * @hwaddr: address to be translated within the memory region
> +     * @flag: requested access permissions
>       */
>      IOMMUTLBEntry (*translate)(IOMMUMemoryRegion *iommu, hwaddr addr,
>                                 IOMMUAccessFlags flag);
> -    /* Returns minimum supported page size */
> +    /* Returns minimum supported page size in bytes.
> +     * If this method is not provided then the minimum is assumed to
> +     * be TARGET_PAGE_SIZE.
> +     *
> +     * @iommu: the IOMMUMemoryRegion
> +     */
>      uint64_t (*get_min_page_size)(IOMMUMemoryRegion *iommu);
> -    /* Called when IOMMU Notifier flag changed */
> +    /* Called when IOMMU Notifier flag changes (ie when the set of
> +     * events which IOMMU users are requesting notification for changes).
> +     * Optional method -- need not be provided if the IOMMU does not
> +     * need to know exactly which events must be notified.
> +     *
> +     * @iommu: the IOMMUMemoryRegion
> +     * @old_flags: events which previously needed to be notified
> +     * @new_flags: events which now need to be notified
> +     */
>      void (*notify_flag_changed)(IOMMUMemoryRegion *iommu,
>                                  IOMMUNotifierFlag old_flags,
>                                  IOMMUNotifierFlag new_flags);
> -    /* Set this up to provide customized IOMMU replay function */
> +    /* Called to handle memory_region_iommu_replay().
> +     *
> +     * The default implementation of memory_region_iommu_replay() is to
> +     * call the IOMMU translate method for every page in the address space
> +     * with flag == IOMMU_NONE and then call the notifier if translate
> +     * returns a valid mapping. If this method is implemented then it
> +     * overrides the default behaviour, and must provide the full semantics
> +     * of memory_region_iommu_replay(), by calling @notifier for every
> +     * translation present in the IOMMU.
> +     *
> +     * Optional method -- an IOMMU only needs to provide this method
> +     * if the default is inefficient or produces undesirable side effects.
> +     *
> +     * Note: this is not related to record-and-replay functionality.
> +     */
>      void (*replay)(IOMMUMemoryRegion *iommu, IOMMUNotifier *notifier);
>
> -    /* Get IOMMU misc attributes */
> -    int (*get_attr)(IOMMUMemoryRegion *iommu, enum IOMMUMemoryRegionAttr,
> +    /* Get IOMMU misc attributes. This is an optional method that
> +     * can be used to allow users of the IOMMU to get implementation-specific
> +     * information. The IOMMU implements this method to handle calls
> +     * by IOMMU users to memory_region_iommu_get_attr() by filling in
> +     * the arbitrary data pointer for any IOMMUMemoryRegionAttr values that
> +     * the IOMMU supports. If the method is unimplemented then
> +     * memory_region_iommu_get_attr() will always return -EINVAL.
> +     *
> +     * @iommu: the IOMMUMemoryRegion
> +     * @attr: attribute being queried
> +     * @data: memory to fill in with the attribute data
> +     *
> +     * Returns 0 on success, or a negative errno; in particular
> +     * returns -EINVAL for unrecognized or unimplemented attribute types.
> +     */
> +    int (*get_attr)(IOMMUMemoryRegion *iommu, enum IOMMUMemoryRegionAttr attr,
>                      void *data);
>  } IOMMUMemoryRegionClass;
>
> @@ -705,6 +776,14 @@ static inline void memory_region_init_reservation(MemoryRegion *mr,
>   * An IOMMU region translates addresses and forwards accesses to a target
>   * memory region.
>   *
> + * The IOMMU implementation must define a subclass of TYPE_IOMMU_MEMORY_REGION.
> + * @_iommu_mr should be a pointer to enough memory for an instance of
> + * that subclass, @instance_size is the size of that subclass, and
> + * @mrtypename is its name. This function will initialize @_iommu_mr as an
> + * instance of the subclass, and its methods will then be called to handle
> + * accesses to the memory region. See the documentation of
> + * #IOMMUMemoryRegionClass for further details.
> + *
>   * @_iommu_mr: the #IOMMUMemoryRegion to be initialized
>   * @instance_size: the IOMMUMemoryRegion subclass instance size
>   * @mrtypename: the type name of the #IOMMUMemoryRegion
> @@ -953,6 +1032,8 @@ void memory_region_register_iommu_notifier(MemoryRegion *mr,
>   * a notifier with the minimum page granularity returned by
>   * mr->iommu_ops->get_page_size().
>   *
> + * Note: this is not related to record-and-replay functionality.
> + *
>   * @iommu_mr: the memory region to observe
>   * @n: the notifier to which to replay iommu mappings
>   */
> @@ -962,6 +1043,8 @@ void memory_region_iommu_replay(IOMMUMemoryRegion *iommu_mr, IOMMUNotifier *n);
>   * memory_region_iommu_replay_all: replay existing IOMMU translations
>   * to all the notifiers registered.
>   *
> + * Note: this is not related to record-and-replay functionality.
> + *
>   * @iommu_mr: the memory region to observe
>   */
>  void memory_region_iommu_replay_all(IOMMUMemoryRegion *iommu_mr);
> @@ -981,7 +1064,9 @@ void memory_region_unregister_iommu_notifier(MemoryRegion *mr,
>   * memory_region_iommu_get_attr: return an IOMMU attr if get_attr() is
>   * defined on the IOMMU.
>   *
> - * Returns 0 if succeded, error code otherwise.
> + * Returns 0 on success, or a negative errno otherwise. In particular,
> + * -EINVAL indicates that the IOMMU does not support the requested
> + * attribute.
>   *
>   * @iommu_mr: the memory region
>   * @attr: the requested attribute


--
Alex Bennée

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 02/27] Make tb_invalidate_phys_addr() take a MemTxAttrs argument
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 02/27] Make tb_invalidate_phys_addr() take a MemTxAttrs argument Peter Maydell
  2018-05-21 23:54   ` Richard Henderson
@ 2018-05-22  9:21   ` Alex Bennée
  1 sibling, 0 replies; 114+ messages in thread
From: Alex Bennée @ 2018-05-22  9:21 UTC (permalink / raw)
  To: Peter Maydell
  Cc: qemu-arm, qemu-devel, patches, Paolo Bonzini, Richard Henderson


Peter Maydell <peter.maydell@linaro.org> writes:

> As part of plumbing MemTxAttrs down to the IOMMU translate method,
> add MemTxAttrs as an argument to tb_invalidate_phys_addr().
> Its callers either have an attrs value to hand, or don't care
> and can use MEMTXATTRS_UNSPECIFIED.
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

> ---
>  include/exec/exec-all.h   | 5 +++--
>  accel/tcg/translate-all.c | 2 +-
>  exec.c                    | 2 +-
>  target/xtensa/op_helper.c | 3 ++-
>  4 files changed, 7 insertions(+), 5 deletions(-)
>
> diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
> index bd68328ed9..4d09eaba72 100644
> --- a/include/exec/exec-all.h
> +++ b/include/exec/exec-all.h
> @@ -255,7 +255,7 @@ void tlb_set_page_with_attrs(CPUState *cpu, target_ulong vaddr,
>  void tlb_set_page(CPUState *cpu, target_ulong vaddr,
>                    hwaddr paddr, int prot,
>                    int mmu_idx, target_ulong size);
> -void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr);
> +void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr, MemTxAttrs attrs);
>  void probe_write(CPUArchState *env, target_ulong addr, int size, int mmu_idx,
>                   uintptr_t retaddr);
>  #else
> @@ -303,7 +303,8 @@ static inline void tlb_flush_by_mmuidx_all_cpus_synced(CPUState *cpu,
>                                                         uint16_t idxmap)
>  {
>  }
> -static inline void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr)
> +static inline void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr,
> +                                           MemTxAttrs attrs)
>  {
>  }
>  #endif
> diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
> index f409d42d54..f04a922ef7 100644
> --- a/accel/tcg/translate-all.c
> +++ b/accel/tcg/translate-all.c
> @@ -1672,7 +1672,7 @@ static TranslationBlock *tb_find_pc(uintptr_t tc_ptr)
>  }
>
>  #if !defined(CONFIG_USER_ONLY)
> -void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr)
> +void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr, MemTxAttrs attrs)
>  {
>      ram_addr_t ram_addr;
>      MemoryRegion *mr;
> diff --git a/exec.c b/exec.c
> index ffa1099547..c3a197e67b 100644
> --- a/exec.c
> +++ b/exec.c
> @@ -898,7 +898,7 @@ static void breakpoint_invalidate(CPUState *cpu, target_ulong pc)
>      if (phys != -1) {
>          /* Locks grabbed by tb_invalidate_phys_addr */
>          tb_invalidate_phys_addr(cpu->cpu_ases[asidx].as,
> -                                phys | (pc & ~TARGET_PAGE_MASK));
> +                                phys | (pc & ~TARGET_PAGE_MASK), attrs);
>      }
>  }
>  #endif
> diff --git a/target/xtensa/op_helper.c b/target/xtensa/op_helper.c
> index e3bcbe10d6..8a8c763c63 100644
> --- a/target/xtensa/op_helper.c
> +++ b/target/xtensa/op_helper.c
> @@ -105,7 +105,8 @@ static void tb_invalidate_virtual_addr(CPUXtensaState *env, uint32_t vaddr)
>      int ret = xtensa_get_physical_addr(env, false, vaddr, 2, 0,
>              &paddr, &page_size, &access);
>      if (ret == 0) {
> -        tb_invalidate_phys_addr(&address_space_memory, paddr);
> +        tb_invalidate_phys_addr(&address_space_memory, paddr,
> +                                MEMTXATTRS_UNSPECIFIED);
>      }
>  }


--
Alex Bennée

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 03/27] Make address_space_translate{, _cached}() take a MemTxAttrs argument
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 03/27] Make address_space_translate{, _cached}() " Peter Maydell
@ 2018-05-22 10:49   ` Alex Bennée
  2018-05-22 16:12   ` Richard Henderson
  1 sibling, 0 replies; 114+ messages in thread
From: Alex Bennée @ 2018-05-22 10:49 UTC (permalink / raw)
  To: Peter Maydell
  Cc: qemu-arm, qemu-devel, patches, Paolo Bonzini, Richard Henderson


Peter Maydell <peter.maydell@linaro.org> writes:

> As part of plumbing MemTxAttrs down to the IOMMU translate method,
> add MemTxAttrs as an argument to address_space_translate()
> and address_space_translate_cached(). Callers either have an
> attrs value to hand, or don't care and can use MEMTXATTRS_UNSPECIFIED.
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Following the chain down I discovered yet another set of not quite
templates leading to the bottom, but not this patches fault...

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

> ---
>  include/exec/memory.h     |  4 +++-
>  accel/tcg/translate-all.c |  2 +-
>  exec.c                    | 14 +++++++++-----
>  hw/vfio/common.c          |  3 ++-
>  memory_ldst.inc.c         | 18 +++++++++---------
>  target/riscv/helper.c     |  2 +-
>  6 files changed, 25 insertions(+), 18 deletions(-)
>
> diff --git a/include/exec/memory.h b/include/exec/memory.h
> index cce355d2d8..9a30a1bb9e 100644
> --- a/include/exec/memory.h
> +++ b/include/exec/memory.h
> @@ -1908,6 +1908,7 @@ IOMMUTLBEntry address_space_get_iotlb_entry(AddressSpace *as, hwaddr addr,
>   * #MemoryRegion.
>   * @len: pointer to length
>   * @is_write: indicates the transfer direction
> + * @attrs: memory attributes
>   */
>  MemoryRegion *flatview_translate(FlatView *fv,
>                                   hwaddr addr, hwaddr *xlat,
> @@ -1915,7 +1916,8 @@ MemoryRegion *flatview_translate(FlatView *fv,
>
>  static inline MemoryRegion *address_space_translate(AddressSpace *as,
>                                                      hwaddr addr, hwaddr *xlat,
> -                                                    hwaddr *len, bool is_write)
> +                                                    hwaddr *len, bool is_write,
> +                                                    MemTxAttrs attrs)
>  {
>      return flatview_translate(address_space_to_flatview(as),
>                                addr, xlat, len, is_write);
> diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
> index f04a922ef7..52f7bd59a9 100644
> --- a/accel/tcg/translate-all.c
> +++ b/accel/tcg/translate-all.c
> @@ -1679,7 +1679,7 @@ void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr, MemTxAttrs attrs)
>      hwaddr l = 1;
>
>      rcu_read_lock();
> -    mr = address_space_translate(as, addr, &addr, &l, false);
> +    mr = address_space_translate(as, addr, &addr, &l, false, attrs);
>      if (!(memory_region_is_ram(mr)
>            || memory_region_is_romd(mr))) {
>          rcu_read_unlock();
> diff --git a/exec.c b/exec.c
> index c3a197e67b..d314c7cc39 100644
> --- a/exec.c
> +++ b/exec.c
> @@ -3322,7 +3322,8 @@ static inline void cpu_physical_memory_write_rom_internal(AddressSpace *as,
>      rcu_read_lock();
>      while (len > 0) {
>          l = len;
> -        mr = address_space_translate(as, addr, &addr1, &l, true);
> +        mr = address_space_translate(as, addr, &addr1, &l, true,
> +                                     MEMTXATTRS_UNSPECIFIED);
>
>          if (!(memory_region_is_ram(mr) ||
>                memory_region_is_romd(mr))) {
> @@ -3699,7 +3700,7 @@ void address_space_cache_destroy(MemoryRegionCache *cache)
>   */
>  static inline MemoryRegion *address_space_translate_cached(
>      MemoryRegionCache *cache, hwaddr addr, hwaddr *xlat,
> -    hwaddr *plen, bool is_write)
> +    hwaddr *plen, bool is_write, MemTxAttrs attrs)
>  {
>      MemoryRegionSection section;
>      MemoryRegion *mr;
> @@ -3733,7 +3734,8 @@ address_space_read_cached_slow(MemoryRegionCache *cache, hwaddr addr,
>      MemoryRegion *mr;
>
>      l = len;
> -    mr = address_space_translate_cached(cache, addr, &addr1, &l, false);
> +    mr = address_space_translate_cached(cache, addr, &addr1, &l, false,
> +                                        MEMTXATTRS_UNSPECIFIED);
>      flatview_read_continue(cache->fv,
>                             addr, MEMTXATTRS_UNSPECIFIED, buf, len,
>                             addr1, l, mr);
> @@ -3750,7 +3752,8 @@ address_space_write_cached_slow(MemoryRegionCache *cache, hwaddr addr,
>      MemoryRegion *mr;
>
>      l = len;
> -    mr = address_space_translate_cached(cache, addr, &addr1, &l, true);
> +    mr = address_space_translate_cached(cache, addr, &addr1, &l, true,
> +                                        MEMTXATTRS_UNSPECIFIED);
>      flatview_write_continue(cache->fv,
>                              addr, MEMTXATTRS_UNSPECIFIED, buf, len,
>                              addr1, l, mr);
> @@ -3848,7 +3851,8 @@ bool cpu_physical_memory_is_io(hwaddr phys_addr)
>
>      rcu_read_lock();
>      mr = address_space_translate(&address_space_memory,
> -                                 phys_addr, &phys_addr, &l, false);
> +                                 phys_addr, &phys_addr, &l, false,
> +                                 MEMTXATTRS_UNSPECIFIED);
>
>      res = !(memory_region_is_ram(mr) || memory_region_is_romd(mr));
>      rcu_read_unlock();
> diff --git a/hw/vfio/common.c b/hw/vfio/common.c
> index 07ffa0ba10..8e57265edf 100644
> --- a/hw/vfio/common.c
> +++ b/hw/vfio/common.c
> @@ -324,7 +324,8 @@ static bool vfio_get_vaddr(IOMMUTLBEntry *iotlb, void **vaddr,
>       */
>      mr = address_space_translate(&address_space_memory,
>                                   iotlb->translated_addr,
> -                                 &xlat, &len, writable);
> +                                 &xlat, &len, writable,
> +                                 MEMTXATTRS_UNSPECIFIED);
>      if (!memory_region_is_ram(mr)) {
>          error_report("iommu map to non memory area %"HWADDR_PRIx"",
>                       xlat);
> diff --git a/memory_ldst.inc.c b/memory_ldst.inc.c
> index 25d6125747..15483987fe 100644
> --- a/memory_ldst.inc.c
> +++ b/memory_ldst.inc.c
> @@ -33,7 +33,7 @@ static inline uint32_t glue(address_space_ldl_internal, SUFFIX)(ARG1_DECL,
>      bool release_lock = false;
>
>      RCU_READ_LOCK();
> -    mr = TRANSLATE(addr, &addr1, &l, false);
> +    mr = TRANSLATE(addr, &addr1, &l, false, attrs);
>      if (l < 4 || !IS_DIRECT(mr, false)) {
>          release_lock |= prepare_mmio_access(mr);
>
> @@ -109,7 +109,7 @@ static inline uint64_t glue(address_space_ldq_internal, SUFFIX)(ARG1_DECL,
>      bool release_lock = false;
>
>      RCU_READ_LOCK();
> -    mr = TRANSLATE(addr, &addr1, &l, false);
> +    mr = TRANSLATE(addr, &addr1, &l, false, attrs);
>      if (l < 8 || !IS_DIRECT(mr, false)) {
>          release_lock |= prepare_mmio_access(mr);
>
> @@ -183,7 +183,7 @@ uint32_t glue(address_space_ldub, SUFFIX)(ARG1_DECL,
>      bool release_lock = false;
>
>      RCU_READ_LOCK();
> -    mr = TRANSLATE(addr, &addr1, &l, false);
> +    mr = TRANSLATE(addr, &addr1, &l, false, attrs);
>      if (!IS_DIRECT(mr, false)) {
>          release_lock |= prepare_mmio_access(mr);
>
> @@ -219,7 +219,7 @@ static inline uint32_t glue(address_space_lduw_internal, SUFFIX)(ARG1_DECL,
>      bool release_lock = false;
>
>      RCU_READ_LOCK();
> -    mr = TRANSLATE(addr, &addr1, &l, false);
> +    mr = TRANSLATE(addr, &addr1, &l, false, attrs);
>      if (l < 2 || !IS_DIRECT(mr, false)) {
>          release_lock |= prepare_mmio_access(mr);
>
> @@ -296,7 +296,7 @@ void glue(address_space_stl_notdirty, SUFFIX)(ARG1_DECL,
>      bool release_lock = false;
>
>      RCU_READ_LOCK();
> -    mr = TRANSLATE(addr, &addr1, &l, true);
> +    mr = TRANSLATE(addr, &addr1, &l, true, attrs);
>      if (l < 4 || !IS_DIRECT(mr, true)) {
>          release_lock |= prepare_mmio_access(mr);
>
> @@ -333,7 +333,7 @@ static inline void glue(address_space_stl_internal, SUFFIX)(ARG1_DECL,
>      bool release_lock = false;
>
>      RCU_READ_LOCK();
> -    mr = TRANSLATE(addr, &addr1, &l, true);
> +    mr = TRANSLATE(addr, &addr1, &l, true, attrs);
>      if (l < 4 || !IS_DIRECT(mr, true)) {
>          release_lock |= prepare_mmio_access(mr);
>
> @@ -405,7 +405,7 @@ void glue(address_space_stb, SUFFIX)(ARG1_DECL,
>      bool release_lock = false;
>
>      RCU_READ_LOCK();
> -    mr = TRANSLATE(addr, &addr1, &l, true);
> +    mr = TRANSLATE(addr, &addr1, &l, true, attrs);
>      if (!IS_DIRECT(mr, true)) {
>          release_lock |= prepare_mmio_access(mr);
>          r = memory_region_dispatch_write(mr, addr1, val, 1, attrs);
> @@ -438,7 +438,7 @@ static inline void glue(address_space_stw_internal, SUFFIX)(ARG1_DECL,
>      bool release_lock = false;
>
>      RCU_READ_LOCK();
> -    mr = TRANSLATE(addr, &addr1, &l, true);
> +    mr = TRANSLATE(addr, &addr1, &l, true, attrs);
>      if (l < 2 || !IS_DIRECT(mr, true)) {
>          release_lock |= prepare_mmio_access(mr);
>
> @@ -511,7 +511,7 @@ static void glue(address_space_stq_internal, SUFFIX)(ARG1_DECL,
>      bool release_lock = false;
>
>      RCU_READ_LOCK();
> -    mr = TRANSLATE(addr, &addr1, &l, true);
> +    mr = TRANSLATE(addr, &addr1, &l, true, attrs);
>      if (l < 8 || !IS_DIRECT(mr, true)) {
>          release_lock |= prepare_mmio_access(mr);
>
> diff --git a/target/riscv/helper.c b/target/riscv/helper.c
> index 95889f23b9..29e1a603dc 100644
> --- a/target/riscv/helper.c
> +++ b/target/riscv/helper.c
> @@ -210,7 +210,7 @@ restart:
>                  MemoryRegion *mr;
>                  hwaddr l = sizeof(target_ulong), addr1;
>                  mr = address_space_translate(cs->as, pte_addr,
> -                    &addr1, &l, false);
> +                    &addr1, &l, false, MEMTXATTRS_UNSPECIFIED);
>                  if (memory_access_is_direct(mr, true)) {
>                      target_ulong *pte_pa =
>                          qemu_map_ram_ptr(mr->ram_block, addr1);


--
Alex Bennée

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 04/27] Make address_space_map() take a MemTxAttrs argument
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 04/27] Make address_space_map() " Peter Maydell
@ 2018-05-22 10:49   ` Alex Bennée
  2018-05-22 16:13   ` Richard Henderson
  1 sibling, 0 replies; 114+ messages in thread
From: Alex Bennée @ 2018-05-22 10:49 UTC (permalink / raw)
  To: Peter Maydell
  Cc: qemu-arm, qemu-devel, patches, Paolo Bonzini, Richard Henderson


Peter Maydell <peter.maydell@linaro.org> writes:

> As part of plumbing MemTxAttrs down to the IOMMU translate method,
> add MemTxAttrs as an argument to address_space_map().
> Its callers either have an attrs value to hand, or don't care
> and can use MEMTXATTRS_UNSPECIFIED.
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

> ---
>  include/exec/memory.h   | 3 ++-
>  include/sysemu/dma.h    | 3 ++-
>  exec.c                  | 6 ++++--
>  target/ppc/mmu-hash64.c | 3 ++-
>  4 files changed, 10 insertions(+), 5 deletions(-)
>
> diff --git a/include/exec/memory.h b/include/exec/memory.h
> index 9a30a1bb9e..b1bdb376d4 100644
> --- a/include/exec/memory.h
> +++ b/include/exec/memory.h
> @@ -1952,9 +1952,10 @@ bool address_space_access_valid(AddressSpace *as, hwaddr addr, int len, bool is_
>   * @addr: address within that address space
>   * @plen: pointer to length of buffer; updated on return
>   * @is_write: indicates the transfer direction
> + * @attrs: memory attributes
>   */
>  void *address_space_map(AddressSpace *as, hwaddr addr,
> -                        hwaddr *plen, bool is_write);
> +                        hwaddr *plen, bool is_write, MemTxAttrs attrs);
>
>  /* address_space_unmap: Unmaps a memory region previously mapped by address_space_map()
>   *
> diff --git a/include/sysemu/dma.h b/include/sysemu/dma.h
> index c228c66513..0d73902634 100644
> --- a/include/sysemu/dma.h
> +++ b/include/sysemu/dma.h
> @@ -132,7 +132,8 @@ static inline void *dma_memory_map(AddressSpace *as,
>      hwaddr xlen = *len;
>      void *p;
>
> -    p = address_space_map(as, addr, &xlen, dir == DMA_DIRECTION_FROM_DEVICE);
> +    p = address_space_map(as, addr, &xlen, dir == DMA_DIRECTION_FROM_DEVICE,
> +                          MEMTXATTRS_UNSPECIFIED);
>      *len = xlen;
>      return p;
>  }
> diff --git a/exec.c b/exec.c
> index d314c7cc39..1dc81cfe4a 100644
> --- a/exec.c
> +++ b/exec.c
> @@ -3529,7 +3529,8 @@ flatview_extend_translation(FlatView *fv, hwaddr addr,
>  void *address_space_map(AddressSpace *as,
>                          hwaddr addr,
>                          hwaddr *plen,
> -                        bool is_write)
> +                        bool is_write,
> +                        MemTxAttrs attrs)
>  {
>      hwaddr len = *plen;
>      hwaddr l, xlat;
> @@ -3616,7 +3617,8 @@ void *cpu_physical_memory_map(hwaddr addr,
>                                hwaddr *plen,
>                                int is_write)
>  {
> -    return address_space_map(&address_space_memory, addr, plen, is_write);
> +    return address_space_map(&address_space_memory, addr, plen, is_write,
> +                             MEMTXATTRS_UNSPECIFIED);
>  }
>
>  void cpu_physical_memory_unmap(void *buffer, hwaddr len,
> diff --git a/target/ppc/mmu-hash64.c b/target/ppc/mmu-hash64.c
> index a1db20e3a8..aa200cba4c 100644
> --- a/target/ppc/mmu-hash64.c
> +++ b/target/ppc/mmu-hash64.c
> @@ -431,7 +431,8 @@ const ppc_hash_pte64_t *ppc_hash64_map_hptes(PowerPCCPU *cpu,
>          return NULL;
>      }
>
> -    hptes = address_space_map(CPU(cpu)->as, base + pte_offset, &plen, false);
> +    hptes = address_space_map(CPU(cpu)->as, base + pte_offset, &plen, false,
> +                              MEMTXATTRS_UNSPECIFIED);
>      if (plen < (n * HASH_PTE_SIZE_64)) {
>          hw_error("%s: Unable to map all requested HPTEs\n", __func__);
>      }


--
Alex Bennée

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 05/27] Make address_space_access_valid() take a MemTxAttrs argument
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 05/27] Make address_space_access_valid() " Peter Maydell
@ 2018-05-22 10:50   ` Alex Bennée
  2018-05-22 16:14   ` Richard Henderson
  1 sibling, 0 replies; 114+ messages in thread
From: Alex Bennée @ 2018-05-22 10:50 UTC (permalink / raw)
  To: Peter Maydell
  Cc: qemu-arm, qemu-devel, patches, Paolo Bonzini, Richard Henderson


Peter Maydell <peter.maydell@linaro.org> writes:

> As part of plumbing MemTxAttrs down to the IOMMU translate method,
> add MemTxAttrs as an argument to address_space_access_valid().
> Its callers either have an attrs value to hand, or don't care
> and can use MEMTXATTRS_UNSPECIFIED.
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

> ---
>  include/exec/memory.h      | 4 +++-
>  include/sysemu/dma.h       | 3 ++-
>  exec.c                     | 3 ++-
>  target/s390x/diag.c        | 6 ++++--
>  target/s390x/excp_helper.c | 3 ++-
>  target/s390x/mmu_helper.c  | 3 ++-
>  target/s390x/sigp.c        | 3 ++-
>  7 files changed, 17 insertions(+), 8 deletions(-)
>
> diff --git a/include/exec/memory.h b/include/exec/memory.h
> index b1bdb376d4..54263bd23b 100644
> --- a/include/exec/memory.h
> +++ b/include/exec/memory.h
> @@ -1937,8 +1937,10 @@ static inline MemoryRegion *address_space_translate(AddressSpace *as,
>   * @addr: address within that address space
>   * @len: length of the area to be checked
>   * @is_write: indicates the transfer direction
> + * @attrs: memory attributes
>   */
> -bool address_space_access_valid(AddressSpace *as, hwaddr addr, int len, bool is_write);
> +bool address_space_access_valid(AddressSpace *as, hwaddr addr, int len,
> +                                bool is_write, MemTxAttrs attrs);
>
>  /* address_space_map: map a physical memory region into a host virtual address
>   *
> diff --git a/include/sysemu/dma.h b/include/sysemu/dma.h
> index 0d73902634..5da3c4e3c5 100644
> --- a/include/sysemu/dma.h
> +++ b/include/sysemu/dma.h
> @@ -77,7 +77,8 @@ static inline bool dma_memory_valid(AddressSpace *as,
>                                      DMADirection dir)
>  {
>      return address_space_access_valid(as, addr, len,
> -                                      dir == DMA_DIRECTION_FROM_DEVICE);
> +                                      dir == DMA_DIRECTION_FROM_DEVICE,
> +                                      MEMTXATTRS_UNSPECIFIED);
>  }
>
>  static inline int dma_memory_rw_relaxed(AddressSpace *as, dma_addr_t addr,
> diff --git a/exec.c b/exec.c
> index 1dc81cfe4a..22af4e8cb9 100644
> --- a/exec.c
> +++ b/exec.c
> @@ -3480,7 +3480,8 @@ static bool flatview_access_valid(FlatView *fv, hwaddr addr, int len,
>  }
>
>  bool address_space_access_valid(AddressSpace *as, hwaddr addr,
> -                                int len, bool is_write)
> +                                int len, bool is_write,
> +                                MemTxAttrs attrs)
>  {
>      FlatView *fv;
>      bool result;
> diff --git a/target/s390x/diag.c b/target/s390x/diag.c
> index ac2c40f363..d1d3433aa7 100644
> --- a/target/s390x/diag.c
> +++ b/target/s390x/diag.c
> @@ -87,7 +87,8 @@ void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra)
>              return;
>          }
>          if (!address_space_access_valid(&address_space_memory, addr,
> -                                        sizeof(IplParameterBlock), false)) {
> +                                        sizeof(IplParameterBlock), false,
> +                                        MEMTXATTRS_UNSPECIFIED)) {
>              s390_program_interrupt(env, PGM_ADDRESSING, ILEN_AUTO, ra);
>              return;
>          }
> @@ -116,7 +117,8 @@ out:
>              return;
>          }
>          if (!address_space_access_valid(&address_space_memory, addr,
> -                                        sizeof(IplParameterBlock), true)) {
> +                                        sizeof(IplParameterBlock), true,
> +                                        MEMTXATTRS_UNSPECIFIED)) {
>              s390_program_interrupt(env, PGM_ADDRESSING, ILEN_AUTO, ra);
>              return;
>          }
> diff --git a/target/s390x/excp_helper.c b/target/s390x/excp_helper.c
> index dfee221111..f0ce60cff2 100644
> --- a/target/s390x/excp_helper.c
> +++ b/target/s390x/excp_helper.c
> @@ -120,7 +120,8 @@ int s390_cpu_handle_mmu_fault(CPUState *cs, vaddr orig_vaddr, int size,
>
>      /* check out of RAM access */
>      if (!address_space_access_valid(&address_space_memory, raddr,
> -                                    TARGET_PAGE_SIZE, rw)) {
> +                                    TARGET_PAGE_SIZE, rw,
> +                                    MEMTXATTRS_UNSPECIFIED)) {
>          DPRINTF("%s: raddr %" PRIx64 " > ram_size %" PRIx64 "\n", __func__,
>                  (uint64_t)raddr, (uint64_t)ram_size);
>          trigger_pgm_exception(env, PGM_ADDRESSING, ILEN_AUTO);
> diff --git a/target/s390x/mmu_helper.c b/target/s390x/mmu_helper.c
> index a25deef5dd..145b62a7ef 100644
> --- a/target/s390x/mmu_helper.c
> +++ b/target/s390x/mmu_helper.c
> @@ -461,7 +461,8 @@ static int translate_pages(S390CPU *cpu, vaddr addr, int nr_pages,
>              return ret;
>          }
>          if (!address_space_access_valid(&address_space_memory, pages[i],
> -                                        TARGET_PAGE_SIZE, is_write)) {
> +                                        TARGET_PAGE_SIZE, is_write,
> +                                        MEMTXATTRS_UNSPECIFIED)) {
>              trigger_access_exception(env, PGM_ADDRESSING, ILEN_AUTO, 0);
>              return -EFAULT;
>          }
> diff --git a/target/s390x/sigp.c b/target/s390x/sigp.c
> index aff1530c82..c1f9245797 100644
> --- a/target/s390x/sigp.c
> +++ b/target/s390x/sigp.c
> @@ -280,7 +280,8 @@ static void sigp_set_prefix(CPUState *cs, run_on_cpu_data arg)
>      cpu_synchronize_state(cs);
>
>      if (!address_space_access_valid(&address_space_memory, addr,
> -                                    sizeof(struct LowCore), false)) {
> +                                    sizeof(struct LowCore), false,
> +                                    MEMTXATTRS_UNSPECIFIED)) {
>          set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
>          return;
>      }


--
Alex Bennée

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 06/27] Make flatview_extend_translation() take a MemTxAttrs argument
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 06/27] Make flatview_extend_translation() " Peter Maydell
@ 2018-05-22 10:56   ` Alex Bennée
  2018-05-22 16:15   ` Richard Henderson
  1 sibling, 0 replies; 114+ messages in thread
From: Alex Bennée @ 2018-05-22 10:56 UTC (permalink / raw)
  To: Peter Maydell
  Cc: qemu-arm, qemu-devel, patches, Paolo Bonzini, Richard Henderson


Peter Maydell <peter.maydell@linaro.org> writes:

> As part of plumbing MemTxAttrs down to the IOMMU translate method,
> add MemTxAttrs as an argument to flatview_extend_translation().
> Its callers either have an attrs value to hand, or don't care
> and can use MEMTXATTRS_UNSPECIFIED.
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

> ---
>  exec.c | 15 ++++++++++-----
>  1 file changed, 10 insertions(+), 5 deletions(-)
>
> diff --git a/exec.c b/exec.c
> index 22af4e8cb9..718b33921b 100644
> --- a/exec.c
> +++ b/exec.c
> @@ -3495,9 +3495,9 @@ bool address_space_access_valid(AddressSpace *as, hwaddr addr,
>
>  static hwaddr
>  flatview_extend_translation(FlatView *fv, hwaddr addr,
> -                                 hwaddr target_len,
> -                                 MemoryRegion *mr, hwaddr base, hwaddr len,
> -                                 bool is_write)
> +                            hwaddr target_len,
> +                            MemoryRegion *mr, hwaddr base, hwaddr len,
> +                            bool is_write, MemTxAttrs attrs)
>  {
>      hwaddr done = 0;
>      hwaddr xlat;
> @@ -3574,7 +3574,7 @@ void *address_space_map(AddressSpace *as,
>
>      memory_region_ref(mr);
>      *plen = flatview_extend_translation(fv, addr, len, mr, xlat,
> -                                             l, is_write);
> +                                        l, is_write, attrs);
>      ptr = qemu_ram_ptr_length(mr->ram_block, xlat, plen, true);
>      rcu_read_unlock();
>
> @@ -3659,8 +3659,13 @@ int64_t address_space_cache_init(MemoryRegionCache *cache,
>      mr = cache->mrs.mr;
>      memory_region_ref(mr);
>      if (memory_access_is_direct(mr, is_write)) {
> +        /* We don't care about the memory attributes here as we're only
> +         * doing this if we found actual RAM, which behaves the same
> +         * regardless of attributes; so UNSPECIFIED is fine.
> +         */
>          l = flatview_extend_translation(cache->fv, addr, len, mr,
> -                                        cache->xlat, l, is_write);
> +                                        cache->xlat, l, is_write,
> +                                        MEMTXATTRS_UNSPECIFIED);
>          cache->ptr = qemu_ram_ptr_length(mr->ram_block, cache->xlat, &l, true);
>      } else {
>          cache->ptr = NULL;


--
Alex Bennée

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 07/27] Make memory_region_access_valid() take a MemTxAttrs argument
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 07/27] Make memory_region_access_valid() " Peter Maydell
@ 2018-05-22 10:57   ` Alex Bennée
  2018-05-22 16:17   ` Richard Henderson
  1 sibling, 0 replies; 114+ messages in thread
From: Alex Bennée @ 2018-05-22 10:57 UTC (permalink / raw)
  To: Peter Maydell
  Cc: qemu-arm, qemu-devel, patches, Paolo Bonzini, Richard Henderson


Peter Maydell <peter.maydell@linaro.org> writes:

> As part of plumbing MemTxAttrs down to the IOMMU translate method,
> add MemTxAttrs as an argument to memory_region_access_valid().
> Its callers either have an attrs value to hand, or don't care
> and can use MEMTXATTRS_UNSPECIFIED.
>
> The callsite in flatview_access_valid() is part of a recursive
> loop flatview_access_valid() -> memory_region_access_valid() ->
>  subpage_accepts() -> flatview_access_valid(); we make it pass
> MEMTXATTRS_UNSPECIFIED for now, until the next several commits
> have plumbed an attrs parameter through the rest of the loop
> and we can add an attrs parameter to flatview_access_valid().
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

> ---
>  include/exec/memory-internal.h | 3 ++-
>  exec.c                         | 4 +++-
>  hw/s390x/s390-pci-inst.c       | 3 ++-
>  memory.c                       | 7 ++++---
>  4 files changed, 11 insertions(+), 6 deletions(-)
>
> diff --git a/include/exec/memory-internal.h b/include/exec/memory-internal.h
> index 58399b9318..56c25c0ef7 100644
> --- a/include/exec/memory-internal.h
> +++ b/include/exec/memory-internal.h
> @@ -37,7 +37,8 @@ void flatview_unref(FlatView *view);
>  extern const MemoryRegionOps unassigned_mem_ops;
>
>  bool memory_region_access_valid(MemoryRegion *mr, hwaddr addr,
> -                                unsigned size, bool is_write);
> +                                unsigned size, bool is_write,
> +                                MemTxAttrs attrs);
>
>  void flatview_add_to_dispatch(FlatView *fv, MemoryRegionSection *section);
>  AddressSpaceDispatch *address_space_dispatch_new(FlatView *fv);
> diff --git a/exec.c b/exec.c
> index 718b33921b..6cf97b5d28 100644
> --- a/exec.c
> +++ b/exec.c
> @@ -3468,7 +3468,9 @@ static bool flatview_access_valid(FlatView *fv, hwaddr addr, int len,
>          mr = flatview_translate(fv, addr, &xlat, &l, is_write);
>          if (!memory_access_is_direct(mr, is_write)) {
>              l = memory_access_size(mr, l, addr);
> -            if (!memory_region_access_valid(mr, xlat, l, is_write)) {
> +            /* When our callers all have attrs we'll pass them through here */
> +            if (!memory_region_access_valid(mr, xlat, l, is_write,
> +                                            MEMTXATTRS_UNSPECIFIED)) {
>                  return false;
>              }
>          }
> diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c
> index 02a815fd31..d1a5f79678 100644
> --- a/hw/s390x/s390-pci-inst.c
> +++ b/hw/s390x/s390-pci-inst.c
> @@ -762,7 +762,8 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr,
>      mr = s390_get_subregion(mr, offset, len);
>      offset -= mr->addr;
>
> -    if (!memory_region_access_valid(mr, offset, len, true)) {
> +    if (!memory_region_access_valid(mr, offset, len, true,
> +                                    MEMTXATTRS_UNSPECIFIED)) {
>          s390_program_interrupt(env, PGM_OPERAND, 6, ra);
>          return 0;
>      }
> diff --git a/memory.c b/memory.c
> index fc7f9b782b..279f7c9b4a 100644
> --- a/memory.c
> +++ b/memory.c
> @@ -1347,7 +1347,8 @@ static const MemoryRegionOps ram_device_mem_ops = {
>  bool memory_region_access_valid(MemoryRegion *mr,
>                                  hwaddr addr,
>                                  unsigned size,
> -                                bool is_write)
> +                                bool is_write,
> +                                MemTxAttrs attrs)
>  {
>      int access_size_min, access_size_max;
>      int access_size, i;
> @@ -1416,7 +1417,7 @@ MemTxResult memory_region_dispatch_read(MemoryRegion *mr,
>  {
>      MemTxResult r;
>
> -    if (!memory_region_access_valid(mr, addr, size, false)) {
> +    if (!memory_region_access_valid(mr, addr, size, false, attrs)) {
>          *pval = unassigned_mem_read(mr, addr, size);
>          return MEMTX_DECODE_ERROR;
>      }
> @@ -1458,7 +1459,7 @@ MemTxResult memory_region_dispatch_write(MemoryRegion *mr,
>                                           unsigned size,
>                                           MemTxAttrs attrs)
>  {
> -    if (!memory_region_access_valid(mr, addr, size, true)) {
> +    if (!memory_region_access_valid(mr, addr, size, true, attrs)) {
>          unassigned_mem_write(mr, addr, data, size);
>          return MEMTX_DECODE_ERROR;
>      }


--
Alex Bennée

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 08/27] Make MemoryRegion valid.accepts callback take a MemTxAttrs argument
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 08/27] Make MemoryRegion valid.accepts callback " Peter Maydell
@ 2018-05-22 10:58   ` Alex Bennée
  2018-05-22 16:20   ` Richard Henderson
  1 sibling, 0 replies; 114+ messages in thread
From: Alex Bennée @ 2018-05-22 10:58 UTC (permalink / raw)
  To: Peter Maydell
  Cc: qemu-arm, qemu-devel, patches, Paolo Bonzini, Richard Henderson


Peter Maydell <peter.maydell@linaro.org> writes:

> As part of plumbing MemTxAttrs down to the IOMMU translate method,
> add MemTxAttrs as an argument to the MemoryRegion valid.accepts
> callback. We'll need this for subpage_accepts().
>
> We could take the approach we used with the read and write
> callbacks and add new a new _with_attrs version, but since there
> are so few implementations of the accepts hook we just change
> them all.
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

> ---
>  include/exec/memory.h |  3 ++-
>  exec.c                |  9 ++++++---
>  hw/hppa/dino.c        |  3 ++-
>  hw/nvram/fw_cfg.c     | 12 ++++++++----
>  hw/scsi/esp.c         |  3 ++-
>  hw/xen/xen_pt_msi.c   |  3 ++-
>  memory.c              |  5 +++--
>  7 files changed, 25 insertions(+), 13 deletions(-)
>
> diff --git a/include/exec/memory.h b/include/exec/memory.h
> index 54263bd23b..444fceac55 100644
> --- a/include/exec/memory.h
> +++ b/include/exec/memory.h
> @@ -166,7 +166,8 @@ struct MemoryRegionOps {
>           * as a machine check exception).
>           */
>          bool (*accepts)(void *opaque, hwaddr addr,
> -                        unsigned size, bool is_write);
> +                        unsigned size, bool is_write,
> +                        MemTxAttrs attrs);
>      } valid;
>      /* Internal implementation constraints: */
>      struct {
> diff --git a/exec.c b/exec.c
> index 6cf97b5d28..b58eb0fedd 100644
> --- a/exec.c
> +++ b/exec.c
> @@ -2539,7 +2539,8 @@ static void notdirty_mem_write(void *opaque, hwaddr ram_addr,
>  }
>
>  static bool notdirty_mem_accepts(void *opaque, hwaddr addr,
> -                                 unsigned size, bool is_write)
> +                                 unsigned size, bool is_write,
> +                                 MemTxAttrs attrs)
>  {
>      return is_write;
>  }
> @@ -2762,7 +2763,8 @@ static MemTxResult subpage_write(void *opaque, hwaddr addr,
>  }
>
>  static bool subpage_accepts(void *opaque, hwaddr addr,
> -                            unsigned len, bool is_write)
> +                            unsigned len, bool is_write,
> +                            MemTxAttrs attrs)
>  {
>      subpage_t *subpage = opaque;
>  #if defined(DEBUG_SUBPAGE)
> @@ -2845,7 +2847,8 @@ static void readonly_mem_write(void *opaque, hwaddr addr,
>  }
>
>  static bool readonly_mem_accepts(void *opaque, hwaddr addr,
> -                                 unsigned size, bool is_write)
> +                                 unsigned size, bool is_write,
> +                                 MemTxAttrs attrs)
>  {
>      return is_write;
>  }
> diff --git a/hw/hppa/dino.c b/hw/hppa/dino.c
> index 15aefde09c..77463672a3 100644
> --- a/hw/hppa/dino.c
> +++ b/hw/hppa/dino.c
> @@ -137,7 +137,8 @@ static void gsc_to_pci_forwarding(DinoState *s)
>  }
>
>  static bool dino_chip_mem_valid(void *opaque, hwaddr addr,
> -                                unsigned size, bool is_write)
> +                                unsigned size, bool is_write,
> +                                MemTxAttrs attrs)
>  {
>      switch (addr) {
>      case DINO_IAR0:
> diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
> index 2a0739d0e9..b23e7f64a8 100644
> --- a/hw/nvram/fw_cfg.c
> +++ b/hw/nvram/fw_cfg.c
> @@ -420,14 +420,16 @@ static void fw_cfg_dma_mem_write(void *opaque, hwaddr addr,
>  }
>
>  static bool fw_cfg_dma_mem_valid(void *opaque, hwaddr addr,
> -                                  unsigned size, bool is_write)
> +                                 unsigned size, bool is_write,
> +                                 MemTxAttrs attrs)
>  {
>      return !is_write || ((size == 4 && (addr == 0 || addr == 4)) ||
>                           (size == 8 && addr == 0));
>  }
>
>  static bool fw_cfg_data_mem_valid(void *opaque, hwaddr addr,
> -                                  unsigned size, bool is_write)
> +                                  unsigned size, bool is_write,
> +                                  MemTxAttrs attrs)
>  {
>      return addr == 0;
>  }
> @@ -439,7 +441,8 @@ static void fw_cfg_ctl_mem_write(void *opaque, hwaddr addr,
>  }
>
>  static bool fw_cfg_ctl_mem_valid(void *opaque, hwaddr addr,
> -                                 unsigned size, bool is_write)
> +                                 unsigned size, bool is_write,
> +                                 MemTxAttrs attrs)
>  {
>      return is_write && size == 2;
>  }
> @@ -458,7 +461,8 @@ static void fw_cfg_comb_write(void *opaque, hwaddr addr,
>  }
>
>  static bool fw_cfg_comb_valid(void *opaque, hwaddr addr,
> -                                  unsigned size, bool is_write)
> +                              unsigned size, bool is_write,
> +                              MemTxAttrs attrs)
>  {
>      return (size == 1) || (is_write && size == 2);
>  }
> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
> index 64ec285826..9ed9727744 100644
> --- a/hw/scsi/esp.c
> +++ b/hw/scsi/esp.c
> @@ -564,7 +564,8 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
>  }
>
>  static bool esp_mem_accepts(void *opaque, hwaddr addr,
> -                            unsigned size, bool is_write)
> +                            unsigned size, bool is_write,
> +                            MemTxAttrs attrs)
>  {
>      return (size == 1) || (is_write && size == 4);
>  }
> diff --git a/hw/xen/xen_pt_msi.c b/hw/xen/xen_pt_msi.c
> index 6d1e3bdeb4..cc514f9157 100644
> --- a/hw/xen/xen_pt_msi.c
> +++ b/hw/xen/xen_pt_msi.c
> @@ -498,7 +498,8 @@ static uint64_t pci_msix_read(void *opaque, hwaddr addr,
>  }
>
>  static bool pci_msix_accepts(void *opaque, hwaddr addr,
> -                             unsigned size, bool is_write)
> +                             unsigned size, bool is_write,
> +                             MemTxAttrs attrs)
>  {
>      return !(addr & (size - 1));
>  }
> diff --git a/memory.c b/memory.c
> index 279f7c9b4a..10fa2ddd31 100644
> --- a/memory.c
> +++ b/memory.c
> @@ -1269,7 +1269,8 @@ static void unassigned_mem_write(void *opaque, hwaddr addr,
>  }
>
>  static bool unassigned_mem_accepts(void *opaque, hwaddr addr,
> -                                   unsigned size, bool is_write)
> +                                   unsigned size, bool is_write,
> +                                   MemTxAttrs attrs)
>  {
>      return false;
>  }
> @@ -1374,7 +1375,7 @@ bool memory_region_access_valid(MemoryRegion *mr,
>      access_size = MAX(MIN(size, access_size_max), access_size_min);
>      for (i = 0; i < size; i += access_size) {
>          if (!mr->ops->valid.accepts(mr->opaque, addr + i, access_size,
> -                                    is_write)) {
> +                                    is_write, attrs)) {
>              return false;
>          }
>      }


--
Alex Bennée

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 09/27] Make flatview_access_valid() take a MemTxAttrs argument
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 09/27] Make flatview_access_valid() " Peter Maydell
@ 2018-05-22 10:58   ` Alex Bennée
  2018-05-22 16:33   ` Richard Henderson
  1 sibling, 0 replies; 114+ messages in thread
From: Alex Bennée @ 2018-05-22 10:58 UTC (permalink / raw)
  To: Peter Maydell
  Cc: qemu-arm, qemu-devel, patches, Paolo Bonzini, Richard Henderson


Peter Maydell <peter.maydell@linaro.org> writes:

> As part of plumbing MemTxAttrs down to the IOMMU translate method,
> add MemTxAttrs as an argument to flatview_access_valid().
> Its callers now all have an attrs value to hand, so we can
> correct our earlier temporary use of MEMTXATTRS_UNSPECIFIED.
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

> ---
>  exec.c | 11 +++++------
>  1 file changed, 5 insertions(+), 6 deletions(-)
>
> diff --git a/exec.c b/exec.c
> index b58eb0fedd..9229fb4058 100644
> --- a/exec.c
> +++ b/exec.c
> @@ -2697,7 +2697,7 @@ static MemTxResult flatview_read(FlatView *fv, hwaddr addr,
>  static MemTxResult flatview_write(FlatView *fv, hwaddr addr, MemTxAttrs attrs,
>                                    const uint8_t *buf, int len);
>  static bool flatview_access_valid(FlatView *fv, hwaddr addr, int len,
> -                                  bool is_write);
> +                                  bool is_write, MemTxAttrs attrs);
>
>  static MemTxResult subpage_read(void *opaque, hwaddr addr, uint64_t *data,
>                                  unsigned len, MemTxAttrs attrs)
> @@ -2773,7 +2773,7 @@ static bool subpage_accepts(void *opaque, hwaddr addr,
>  #endif
>
>      return flatview_access_valid(subpage->fv, addr + subpage->base,
> -                                 len, is_write);
> +                                 len, is_write, attrs);
>  }
>
>  static const MemoryRegionOps subpage_ops = {
> @@ -3461,7 +3461,7 @@ static void cpu_notify_map_clients(void)
>  }
>
>  static bool flatview_access_valid(FlatView *fv, hwaddr addr, int len,
> -                                  bool is_write)
> +                                  bool is_write, MemTxAttrs attrs)
>  {
>      MemoryRegion *mr;
>      hwaddr l, xlat;
> @@ -3472,8 +3472,7 @@ static bool flatview_access_valid(FlatView *fv, hwaddr addr, int len,
>          if (!memory_access_is_direct(mr, is_write)) {
>              l = memory_access_size(mr, l, addr);
>              /* When our callers all have attrs we'll pass them through here */
> -            if (!memory_region_access_valid(mr, xlat, l, is_write,
> -                                            MEMTXATTRS_UNSPECIFIED)) {
> +            if (!memory_region_access_valid(mr, xlat, l, is_write, attrs)) {
>                  return false;
>              }
>          }
> @@ -3493,7 +3492,7 @@ bool address_space_access_valid(AddressSpace *as, hwaddr addr,
>
>      rcu_read_lock();
>      fv = address_space_to_flatview(as);
> -    result = flatview_access_valid(fv, addr, len, is_write);
> +    result = flatview_access_valid(fv, addr, len, is_write, attrs);
>      rcu_read_unlock();
>      return result;
>  }


--
Alex Bennée

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 10/27] Make flatview_translate() take a MemTxAttrs argument
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 10/27] Make flatview_translate() " Peter Maydell
@ 2018-05-22 10:58   ` Alex Bennée
  2018-05-22 16:33   ` Richard Henderson
  1 sibling, 0 replies; 114+ messages in thread
From: Alex Bennée @ 2018-05-22 10:58 UTC (permalink / raw)
  To: Peter Maydell
  Cc: qemu-arm, qemu-devel, patches, Paolo Bonzini, Richard Henderson


Peter Maydell <peter.maydell@linaro.org> writes:

> As part of plumbing MemTxAttrs down to the IOMMU translate method,
> add MemTxAttrs as an argument to flatview_translate(); all its
> callers now have attrs available.
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

> ---
>  include/exec/memory.h |  7 ++++---
>  exec.c                | 17 +++++++++--------
>  2 files changed, 13 insertions(+), 11 deletions(-)
>
> diff --git a/include/exec/memory.h b/include/exec/memory.h
> index 444fceac55..3980ab47ed 100644
> --- a/include/exec/memory.h
> +++ b/include/exec/memory.h
> @@ -1913,7 +1913,8 @@ IOMMUTLBEntry address_space_get_iotlb_entry(AddressSpace *as, hwaddr addr,
>   */
>  MemoryRegion *flatview_translate(FlatView *fv,
>                                   hwaddr addr, hwaddr *xlat,
> -                                 hwaddr *len, bool is_write);
> +                                 hwaddr *len, bool is_write,
> +                                 MemTxAttrs attrs);
>
>  static inline MemoryRegion *address_space_translate(AddressSpace *as,
>                                                      hwaddr addr, hwaddr *xlat,
> @@ -1921,7 +1922,7 @@ static inline MemoryRegion *address_space_translate(AddressSpace *as,
>                                                      MemTxAttrs attrs)
>  {
>      return flatview_translate(address_space_to_flatview(as),
> -                              addr, xlat, len, is_write);
> +                              addr, xlat, len, is_write, attrs);
>  }
>
>  /* address_space_access_valid: check for validity of accessing an address
> @@ -2030,7 +2031,7 @@ MemTxResult address_space_read(AddressSpace *as, hwaddr addr,
>              rcu_read_lock();
>              fv = address_space_to_flatview(as);
>              l = len;
> -            mr = flatview_translate(fv, addr, &addr1, &l, false);
> +            mr = flatview_translate(fv, addr, &addr1, &l, false, attrs);
>              if (len == l && memory_access_is_direct(mr, false)) {
>                  ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
>                  memcpy(buf, ptr, len);
> diff --git a/exec.c b/exec.c
> index 9229fb4058..b818ba87f4 100644
> --- a/exec.c
> +++ b/exec.c
> @@ -618,7 +618,8 @@ iotlb_fail:
>
>  /* Called from RCU critical section */
>  MemoryRegion *flatview_translate(FlatView *fv, hwaddr addr, hwaddr *xlat,
> -                                 hwaddr *plen, bool is_write)
> +                                 hwaddr *plen, bool is_write,
> +                                 MemTxAttrs attrs)
>  {
>      MemoryRegion *mr;
>      MemoryRegionSection section;
> @@ -3152,7 +3153,7 @@ static MemTxResult flatview_write_continue(FlatView *fv, hwaddr addr,
>          }
>
>          l = len;
> -        mr = flatview_translate(fv, addr, &addr1, &l, true);
> +        mr = flatview_translate(fv, addr, &addr1, &l, true, attrs);
>      }
>
>      return result;
> @@ -3168,7 +3169,7 @@ static MemTxResult flatview_write(FlatView *fv, hwaddr addr, MemTxAttrs attrs,
>      MemTxResult result = MEMTX_OK;
>
>      l = len;
> -    mr = flatview_translate(fv, addr, &addr1, &l, true);
> +    mr = flatview_translate(fv, addr, &addr1, &l, true, attrs);
>      result = flatview_write_continue(fv, addr, attrs, buf, len,
>                                       addr1, l, mr);
>
> @@ -3239,7 +3240,7 @@ MemTxResult flatview_read_continue(FlatView *fv, hwaddr addr,
>          }
>
>          l = len;
> -        mr = flatview_translate(fv, addr, &addr1, &l, false);
> +        mr = flatview_translate(fv, addr, &addr1, &l, false, attrs);
>      }
>
>      return result;
> @@ -3254,7 +3255,7 @@ static MemTxResult flatview_read(FlatView *fv, hwaddr addr,
>      MemoryRegion *mr;
>
>      l = len;
> -    mr = flatview_translate(fv, addr, &addr1, &l, false);
> +    mr = flatview_translate(fv, addr, &addr1, &l, false, attrs);
>      return flatview_read_continue(fv, addr, attrs, buf, len,
>                                    addr1, l, mr);
>  }
> @@ -3468,7 +3469,7 @@ static bool flatview_access_valid(FlatView *fv, hwaddr addr, int len,
>
>      while (len > 0) {
>          l = len;
> -        mr = flatview_translate(fv, addr, &xlat, &l, is_write);
> +        mr = flatview_translate(fv, addr, &xlat, &l, is_write, attrs);
>          if (!memory_access_is_direct(mr, is_write)) {
>              l = memory_access_size(mr, l, addr);
>              /* When our callers all have attrs we'll pass them through here */
> @@ -3517,7 +3518,7 @@ flatview_extend_translation(FlatView *fv, hwaddr addr,
>
>          len = target_len;
>          this_mr = flatview_translate(fv, addr, &xlat,
> -                                                   &len, is_write);
> +                                     &len, is_write, attrs);
>          if (this_mr != mr || xlat != base + done) {
>              return done;
>          }
> @@ -3550,7 +3551,7 @@ void *address_space_map(AddressSpace *as,
>      l = len;
>      rcu_read_lock();
>      fv = address_space_to_flatview(as);
> -    mr = flatview_translate(fv, addr, &xlat, &l, is_write);
> +    mr = flatview_translate(fv, addr, &xlat, &l, is_write, attrs);
>
>      if (!memory_access_is_direct(mr, is_write)) {
>          if (atomic_xchg(&bounce.in_use, true)) {


--
Alex Bennée

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 11/27] Make address_space_get_iotlb_entry() take a MemTxAttrs argument
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 11/27] Make address_space_get_iotlb_entry() " Peter Maydell
@ 2018-05-22 11:00   ` Alex Bennée
  2018-05-22 17:29   ` Richard Henderson
  1 sibling, 0 replies; 114+ messages in thread
From: Alex Bennée @ 2018-05-22 11:00 UTC (permalink / raw)
  To: Peter Maydell
  Cc: qemu-arm, qemu-devel, patches, Paolo Bonzini, Richard Henderson


Peter Maydell <peter.maydell@linaro.org> writes:

> As part of plumbing MemTxAttrs down to the IOMMU translate method,
> add MemTxAttrs as an argument to address_space_get_iotlb_entry().
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

> ---
>  include/exec/memory.h | 2 +-
>  exec.c                | 2 +-
>  hw/virtio/vhost.c     | 3 ++-
>  3 files changed, 4 insertions(+), 3 deletions(-)
>
> diff --git a/include/exec/memory.h b/include/exec/memory.h
> index 3980ab47ed..309fdfb89b 100644
> --- a/include/exec/memory.h
> +++ b/include/exec/memory.h
> @@ -1896,7 +1896,7 @@ void address_space_cache_destroy(MemoryRegionCache *cache);
>   * entry. Should be called from an RCU critical section.
>   */
>  IOMMUTLBEntry address_space_get_iotlb_entry(AddressSpace *as, hwaddr addr,
> -                                            bool is_write);
> +                                            bool is_write, MemTxAttrs attrs);
>
>  /* address_space_translate: translate an address range into an address space
>   * into a MemoryRegion and an address range into that section.  Should be
> diff --git a/exec.c b/exec.c
> index b818ba87f4..84f2c21ecb 100644
> --- a/exec.c
> +++ b/exec.c
> @@ -582,7 +582,7 @@ static MemoryRegionSection flatview_do_translate(FlatView *fv,
>
>  /* Called from RCU critical section */
>  IOMMUTLBEntry address_space_get_iotlb_entry(AddressSpace *as, hwaddr addr,
> -                                            bool is_write)
> +                                            bool is_write, MemTxAttrs attrs)
>  {
>      MemoryRegionSection section;
>      hwaddr xlat, page_mask;
> diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
> index 9d5850a7d7..48f4fd7cc9 100644
> --- a/hw/virtio/vhost.c
> +++ b/hw/virtio/vhost.c
> @@ -895,7 +895,8 @@ int vhost_device_iotlb_miss(struct vhost_dev *dev, uint64_t iova, int write)
>      rcu_read_lock();
>
>      iotlb = address_space_get_iotlb_entry(dev->vdev->dma_as,
> -                                          iova, write);
> +                                          iova, write,
> +                                          MEMTXATTRS_UNSPECIFIED);
>      if (iotlb.target_as != NULL) {
>          ret = vhost_memory_region_lookup(dev, iotlb.translated_addr,
>                                           &uaddr, &len);


--
Alex Bennée

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 12/27] Make flatview_do_translate() take a MemTxAttrs argument
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 12/27] Make flatview_do_translate() " Peter Maydell
@ 2018-05-22 11:00   ` Alex Bennée
  2018-05-22 17:29   ` Richard Henderson
  1 sibling, 0 replies; 114+ messages in thread
From: Alex Bennée @ 2018-05-22 11:00 UTC (permalink / raw)
  To: Peter Maydell
  Cc: qemu-arm, qemu-devel, patches, Paolo Bonzini, Richard Henderson


Peter Maydell <peter.maydell@linaro.org> writes:

> As part of plumbing MemTxAttrs down to the IOMMU translate method,
> add MemTxAttrs as an argument to flatview_do_translate().
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

> ---
>  exec.c | 9 ++++++---
>  1 file changed, 6 insertions(+), 3 deletions(-)
>
> diff --git a/exec.c b/exec.c
> index 84f2c21ecb..af2b82d154 100644
> --- a/exec.c
> +++ b/exec.c
> @@ -541,6 +541,7 @@ unassigned:
>   * @is_write: whether the translation operation is for write
>   * @is_mmio: whether this can be MMIO, set true if it can
>   * @target_as: the address space targeted by the IOMMU
> + * @attrs: memory transaction attributes
>   *
>   * This function is called from RCU critical section
>   */
> @@ -551,7 +552,8 @@ static MemoryRegionSection flatview_do_translate(FlatView *fv,
>                                                   hwaddr *page_mask_out,
>                                                   bool is_write,
>                                                   bool is_mmio,
> -                                                 AddressSpace **target_as)
> +                                                 AddressSpace **target_as,
> +                                                 MemTxAttrs attrs)
>  {
>      MemoryRegionSection *section;
>      IOMMUMemoryRegion *iommu_mr;
> @@ -592,7 +594,8 @@ IOMMUTLBEntry address_space_get_iotlb_entry(AddressSpace *as, hwaddr addr,
>       * but page mask.
>       */
>      section = flatview_do_translate(address_space_to_flatview(as), addr, &xlat,
> -                                    NULL, &page_mask, is_write, false, &as);
> +                                    NULL, &page_mask, is_write, false, &as,
> +                                    attrs);
>
>      /* Illegal translation */
>      if (section.mr == &io_mem_unassigned) {
> @@ -627,7 +630,7 @@ MemoryRegion *flatview_translate(FlatView *fv, hwaddr addr, hwaddr *xlat,
>
>      /* This can be MMIO, so setup MMIO bit. */
>      section = flatview_do_translate(fv, addr, xlat, plen, NULL,
> -                                    is_write, true, &as);
> +                                    is_write, true, &as, attrs);
>      mr = section.mr;
>
>      if (xen_enabled() && memory_access_is_direct(mr, is_write)) {


--
Alex Bennée

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 13/27] Make address_space_translate_iommu take a MemTxAttrs argument
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 13/27] Make address_space_translate_iommu " Peter Maydell
@ 2018-05-22 11:00   ` Alex Bennée
  2018-05-22 17:30   ` Richard Henderson
  1 sibling, 0 replies; 114+ messages in thread
From: Alex Bennée @ 2018-05-22 11:00 UTC (permalink / raw)
  To: Peter Maydell
  Cc: qemu-arm, qemu-devel, patches, Paolo Bonzini, Richard Henderson


Peter Maydell <peter.maydell@linaro.org> writes:

> As part of plumbing MemTxAttrs down to the IOMMU translate method,
> add MemTxAttrs as an argument to address_space_translate_iommu().
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

> ---
>  exec.c | 8 +++++---
>  1 file changed, 5 insertions(+), 3 deletions(-)
>
> diff --git a/exec.c b/exec.c
> index af2b82d154..c3baadc349 100644
> --- a/exec.c
> +++ b/exec.c
> @@ -478,6 +478,7 @@ address_space_translate_internal(AddressSpaceDispatch *d, hwaddr addr, hwaddr *x
>   * @is_write: whether the translation operation is for write
>   * @is_mmio: whether this can be MMIO, set true if it can
>   * @target_as: the address space targeted by the IOMMU
> + * @attrs: transaction attributes
>   *
>   * This function is called from RCU critical section.  It is the common
>   * part of flatview_do_translate and address_space_translate_cached.
> @@ -488,7 +489,8 @@ static MemoryRegionSection address_space_translate_iommu(IOMMUMemoryRegion *iomm
>                                                           hwaddr *page_mask_out,
>                                                           bool is_write,
>                                                           bool is_mmio,
> -                                                         AddressSpace **target_as)
> +                                                         AddressSpace **target_as,
> +                                                         MemTxAttrs attrs)
>  {
>      MemoryRegionSection *section;
>      hwaddr page_mask = (hwaddr)-1;
> @@ -572,7 +574,7 @@ static MemoryRegionSection flatview_do_translate(FlatView *fv,
>          return address_space_translate_iommu(iommu_mr, xlat,
>                                               plen_out, page_mask_out,
>                                               is_write, is_mmio,
> -                                             target_as);
> +                                             target_as, attrs);
>      }
>      if (page_mask_out) {
>          /* Not behind an IOMMU, use default page size. */
> @@ -3735,7 +3737,7 @@ static inline MemoryRegion *address_space_translate_cached(
>
>      section = address_space_translate_iommu(iommu_mr, xlat, plen,
>                                              NULL, is_write, true,
> -                                            &target_as);
> +                                            &target_as, attrs);
>      return section.mr;
>  }


--
Alex Bennée

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 14/27] iommu: Add IOMMU index concept to IOMMU API
  2018-05-22  8:40     ` Peter Maydell
@ 2018-05-22 11:02       ` Peter Xu
  2018-05-22 11:11         ` Peter Maydell
  0 siblings, 1 reply; 114+ messages in thread
From: Peter Xu @ 2018-05-22 11:02 UTC (permalink / raw)
  To: Peter Maydell
  Cc: qemu-arm, QEMU Developers, Paolo Bonzini, Richard Henderson,
	Alex Bennée, patches, David Gibson, Alex Williamson

On Tue, May 22, 2018 at 09:40:44AM +0100, Peter Maydell wrote:
> On 22 May 2018 at 04:03, Peter Xu <peterx@redhat.com> wrote:
> > On Mon, May 21, 2018 at 03:03:49PM +0100, Peter Maydell wrote:
> >> If an IOMMU supports mappings that care about the memory
> >> transaction attributes, then it no longer has a unique
> >> address -> output mapping, but more than one. We can
> >> represent these using an IOMMU index, analogous to TCG's
> >> mmu indexes.
> >>
> >> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> >> ---
> >>  include/exec/memory.h | 52 +++++++++++++++++++++++++++++++++++++++++++
> >>  memory.c              | 23 +++++++++++++++++++
> >>  2 files changed, 75 insertions(+)
> >>
> >> diff --git a/include/exec/memory.h b/include/exec/memory.h
> >> index 309fdfb89b..f6226fb263 100644
> >> --- a/include/exec/memory.h
> >> +++ b/include/exec/memory.h
> >> @@ -206,6 +206,20 @@ enum IOMMUMemoryRegionAttr {
> >>   * to report whenever mappings are changed, by calling
> >>   * memory_region_notify_iommu() (or, if necessary, by calling
> >>   * memory_region_notify_one() for each registered notifier).
> >> + *
> >> + * Conceptually an IOMMU provides a mapping from input address
> >> + * to an output TLB entry. If the IOMMU is aware of memory transaction
> >> + * attributes and the output TLB entry depends on the transaction
> >> + * attributes, we represent this using IOMMU indexes. Each index
> >
> > Hi, Peter,
> >
> > In what case will an IOMMU translation depend on translation
> > attributes?  It seems to me that we should always pass in the
> > translation attributes into the translate() function.  The translate()
> > function can omit that parameter if the specific IOMMU does not need
> > that information, but still I am confused about why we need to index
> > IOMMU by translation attributes.
> 
> The MPC implementation at the tail end of the patchset is
> one example -- it needs to look at attrs.secure, because
> "translation for secure access to address X" differs from
> that for address Y". The Arm SMMUv3 is the same when it supports
> TrustZone (the implementation in-tree does not), and it can also
> give different permissions for transactions with attrs.user = 0 vs 1.

Thanks for providing more context.

> 
> The reason for not just passing in the transaction attributes to
> translate is that
> (a) the iommu index abstraction makes the notifier setup simpler:
> rather than having to have some indication in the API of which
> of the transaction attributes are important and which the notifier
> cares about, we can just use indexs

Hmm, so here IIUC we'll have a new IOMMU notifier that will only
listen to part of the IOMMU notifies, e.g., when attrs.secure=true.
Yes I think adding something into IOMMUNotifier might work, but just
to mention that in IOMMUTLBEntry we have IOMMUTLBEntry.target_as
defined.  Until now it's hardly used at least on x86 platform since
all of the translations on x86 are targeted to the system RAM.
However it seems to be quite tailored in this case since it seems to
me that different attrs.secure value for translations should be based
on different address spaces too.  Then in the IOMMU notifiers that
would care about MemTxAttrs, could it be possible to identify that by
check against the IOMMUTLBEntry.target_as?

> (b) it means that it's harder to write an iommu with the bug that
> it looks at parts of the transaction attributes that it didn't
> claim were important in the notifier API

It is just confusing to me when I looked at current translate()
interface (I copied it from some other patch of the series):

@@ -252,9 +252,10 @@ typedef struct IOMMUMemoryRegionClass {
      * @iommu: the IOMMUMemoryRegion
      * @hwaddr: address to be translated within the memory region
      * @flag: requested access permissions
+     * @iommu_idx: IOMMU index for the translation
      */
     IOMMUTLBEntry (*translate)(IOMMUMemoryRegion *iommu, hwaddr addr,
-                               IOMMUAccessFlags flag);
+                               IOMMUAccessFlags flag, int iommu_idx);

The "iommu_idx" parameter is really hard to understand here at the
first glance.  Now I think I understand that it is somehow related to
the MemTxAttrs, but still it will take time to understand.

And if we see current implementation for this (still, I copied code
from other patch in the series to here to ease discussion):

@@ -498,8 +498,15 @@ static MemoryRegionSection address_space_translate_iommu(IOMMUMemoryRegion *iomm
     do {
         hwaddr addr = *xlat;
         IOMMUMemoryRegionClass *imrc = memory_region_get_iommu_class_nocheck(iommu_mr);
-        IOMMUTLBEntry iotlb = imrc->translate(iommu_mr, addr, is_write ?
-                                              IOMMU_WO : IOMMU_RO);
+        int iommu_idx = 0;
+        IOMMUTLBEntry iotlb;
+
+        if (imrc->attrs_to_index) {
+            iommu_idx = imrc->attrs_to_index(iommu_mr, attrs);
+        }
+
+        iotlb = imrc->translate(iommu_mr, addr, is_write ?
+                                IOMMU_WO : IOMMU_RO, iommu_idx);

Here what if we pass attrs directly into imrc->translate() and just
call imrc->attrs_to_index() inside the arch-dependent translate()
function?  Will that work too?

I had a quick glance at the series, I have no thorough idea on the
whole stuff, but I'd say some of the patches are exactly what I wanted
if to support MemTxAttrs in VT-d emulation one day (now DMAR of VT-d
is bypassing MemTxAttrs and IMHO that's incorrect).  If we can somehow
pass in the MemTxAttrs then that'll be perfect and I can continue to
work on that.  If we pass in iommu_idx now instead, it would take some
time for me to figure out how to further achieve the same goal for
VT-d in the future, e.g., I would still want to pass in MemTxAttrs,
but that's obviously duplicated with iommu_idx.

(Also CCing David and Alex)

Thanks,

-- 
Peter Xu

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 14/27] iommu: Add IOMMU index concept to IOMMU API
  2018-05-22 11:02       ` Peter Xu
@ 2018-05-22 11:11         ` Peter Maydell
  2018-05-23  1:06           ` Peter Xu
  0 siblings, 1 reply; 114+ messages in thread
From: Peter Maydell @ 2018-05-22 11:11 UTC (permalink / raw)
  To: Peter Xu
  Cc: qemu-arm, QEMU Developers, Paolo Bonzini, Richard Henderson,
	Alex Bennée, patches, David Gibson, Alex Williamson

On 22 May 2018 at 12:02, Peter Xu <peterx@redhat.com> wrote:
> On Tue, May 22, 2018 at 09:40:44AM +0100, Peter Maydell wrote:
>> On 22 May 2018 at 04:03, Peter Xu <peterx@redhat.com> wrote:
>> The reason for not just passing in the transaction attributes to
>> translate is that
>> (a) the iommu index abstraction makes the notifier setup simpler:
>> rather than having to have some indication in the API of which
>> of the transaction attributes are important and which the notifier
>> cares about, we can just use indexs
>
> Hmm, so here IIUC we'll have a new IOMMU notifier that will only
> listen to part of the IOMMU notifies, e.g., when attrs.secure=true.
> Yes I think adding something into IOMMUNotifier might work, but just
> to mention that in IOMMUTLBEntry we have IOMMUTLBEntry.target_as
> defined.  Until now it's hardly used at least on x86 platform since
> all of the translations on x86 are targeted to the system RAM.
> However it seems to be quite tailored in this case since it seems to
> me that different attrs.secure value for translations should be based
> on different address spaces too.  Then in the IOMMU notifiers that
> would care about MemTxAttrs, could it be possible to identify that by
> check against the IOMMUTLBEntry.target_as?

No, because you can have a single address space that receives
transactions with various attributes. (Again, the MPC is an
example of this.)

>> (b) it means that it's harder to write an iommu with the bug that
>> it looks at parts of the transaction attributes that it didn't
>> claim were important in the notifier API
>
> It is just confusing to me when I looked at current translate()
> interface (I copied it from some other patch of the series):
>
> @@ -252,9 +252,10 @@ typedef struct IOMMUMemoryRegionClass {
>       * @iommu: the IOMMUMemoryRegion
>       * @hwaddr: address to be translated within the memory region
>       * @flag: requested access permissions
> +     * @iommu_idx: IOMMU index for the translation
>       */
>      IOMMUTLBEntry (*translate)(IOMMUMemoryRegion *iommu, hwaddr addr,
> -                               IOMMUAccessFlags flag);
> +                               IOMMUAccessFlags flag, int iommu_idx);
>
> The "iommu_idx" parameter is really hard to understand here at the
> first glance.  Now I think I understand that it is somehow related to
> the MemTxAttrs, but still it will take time to understand.

The part of the documentation where I try to explain the general
idea is in this patch, in the comment at the top of the struct:

+ * Conceptually an IOMMU provides a mapping from input address
+ * to an output TLB entry. If the IOMMU is aware of memory transaction
+ * attributes and the output TLB entry depends on the transaction
+ * attributes, we represent this using IOMMU indexes. Each index
+ * selects a particular translation table that the IOMMU has:
+ *   @attrs_to_index returns the IOMMU index for a set of transaction
attributes
+ *   @translate takes an input address and an IOMMU index
+ * and the mapping returned can only depend on the input address and the
+ * IOMMU index.
+ *
+ * Most IOMMUs don't care about the transaction attributes and support
+ * only a single IOMMU index. A more complex IOMMU might have one index
+ * for secure transactions and one for non-secure transactions.

Do you have suggestions for how to improve on this?

> And if we see current implementation for this (still, I copied code
> from other patch in the series to here to ease discussion):
>
> @@ -498,8 +498,15 @@ static MemoryRegionSection address_space_translate_iommu(IOMMUMemoryRegion *iomm
>      do {
>          hwaddr addr = *xlat;
>          IOMMUMemoryRegionClass *imrc = memory_region_get_iommu_class_nocheck(iommu_mr);
> -        IOMMUTLBEntry iotlb = imrc->translate(iommu_mr, addr, is_write ?
> -                                              IOMMU_WO : IOMMU_RO);
> +        int iommu_idx = 0;
> +        IOMMUTLBEntry iotlb;
> +
> +        if (imrc->attrs_to_index) {
> +            iommu_idx = imrc->attrs_to_index(iommu_mr, attrs);
> +        }
> +
> +        iotlb = imrc->translate(iommu_mr, addr, is_write ?
> +                                IOMMU_WO : IOMMU_RO, iommu_idx);
>
> Here what if we pass attrs directly into imrc->translate() and just
> call imrc->attrs_to_index() inside the arch-dependent translate()
> function?  Will that work too?

You don't always have the attributes at the point where you want
to call translate. (For instance, memory_region_notify_iommu()
doesn't have attributes.)

I started off with "pass the tx attrs into the translate method",
which is fine for the code flows which are actually doing
memory transactions, but breaks down when you try to incorporate
notifiers.

> I had a quick glance at the series, I have no thorough idea on the
> whole stuff, but I'd say some of the patches are exactly what I wanted
> if to support MemTxAttrs in VT-d emulation one day (now DMAR of VT-d
> is bypassing MemTxAttrs and IMHO that's incorrect).  If we can somehow
> pass in the MemTxAttrs then that'll be perfect and I can continue to
> work on that.  If we pass in iommu_idx now instead, it would take some
> time for me to figure out how to further achieve the same goal for
> VT-d in the future, e.g., I would still want to pass in MemTxAttrs,
> but that's obviously duplicated with iommu_idx.

The idea is that you should never need to pass in the MemTxAttrs,
because everything that the IOMMU might care about in the tx attrs
must be encoded into the iommu index. (The point where the IOMMU
gets to do that encoding is in its attrs_to_index() method.)

thanks
-- PMM

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 18/27] hw/misc/tz-mpc.c: Implement the Arm TrustZone Memory Protection Controller
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 18/27] hw/misc/tz-mpc.c: Implement the Arm TrustZone Memory Protection Controller Peter Maydell
@ 2018-05-22 11:30   ` Auger Eric
  2018-05-22 11:56     ` Peter Maydell
  2018-05-23 10:41   ` Alex Bennée
  1 sibling, 1 reply; 114+ messages in thread
From: Auger Eric @ 2018-05-22 11:30 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel
  Cc: Paolo Bonzini, Richard Henderson, Alex Bennée, patches

Hi Peter,

On 05/21/2018 04:03 PM, Peter Maydell wrote:
> Implement the Arm TrustZone Memory Protection Controller, which sits
> in front of RAM and allows secure software to configure it to either
> pass through or reject transactions.
> 
> We implement the MPC as a QEMU IOMMU, which will direct transactions
> either through to the devices and memory behind it or to a special
> "never works" AddressSpace if they are blocked.
> 
> This initial commit implements the skeleton of the device:
>  * it always permits accesses
>  * it doesn't implement most of the registers
>  * it doesn't implement the interrupt or other behaviour
>    for blocked transactions
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

this patch does not seem to apply on master.

Thanks

Eric
> ---
>  hw/misc/Makefile.objs           |   1 +
>  include/hw/misc/tz-mpc.h        |  70 ++++++
>  hw/misc/tz-mpc.c                | 381 ++++++++++++++++++++++++++++++++
>  MAINTAINERS                     |   2 +
>  default-configs/arm-softmmu.mak |   1 +
>  hw/misc/trace-events            |   7 +
>  6 files changed, 462 insertions(+)
>  create mode 100644 include/hw/misc/tz-mpc.h
>  create mode 100644 hw/misc/tz-mpc.c
> 
> diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
> index 00e834d0f0..7295e676a6 100644
> --- a/hw/misc/Makefile.objs
> +++ b/hw/misc/Makefile.objs
> @@ -61,6 +61,7 @@ obj-$(CONFIG_MIPS_ITU) += mips_itu.o
>  obj-$(CONFIG_MPS2_FPGAIO) += mps2-fpgaio.o
>  obj-$(CONFIG_MPS2_SCC) += mps2-scc.o
>  
> +obj-$(CONFIG_TZ_MPC) += tz-mpc.o
>  obj-$(CONFIG_TZ_PPC) += tz-ppc.o
>  obj-$(CONFIG_IOTKIT_SECCTL) += iotkit-secctl.o
>  
> diff --git a/include/hw/misc/tz-mpc.h b/include/hw/misc/tz-mpc.h
> new file mode 100644
> index 0000000000..b5eaf1699e
> --- /dev/null
> +++ b/include/hw/misc/tz-mpc.h
> @@ -0,0 +1,70 @@
> +/*
> + * ARM TrustZone memory protection controller emulation
> + *
> + * Copyright (c) 2018 Linaro Limited
> + * Written by Peter Maydell
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 or
> + * (at your option) any later version.
> + */
> +
> +/* This is a model of the TrustZone memory protection controller (MPC).
> + * It is documented in the ARM CoreLink SIE-200 System IP for Embedded TRM
> + * (DDI 0571G):
> + * https://developer.arm.com/products/architecture/m-profile/docs/ddi0571/g
> + *
> + * The MPC sits in front of memory and allows secure software to
> + * configure it to either pass through or reject transactions.
> + * Rejected transactions may be configured to either be aborted, or to
> + * behave as RAZ/WI. An interrupt can be signalled for a rejected transaction.
> + *
> + * The MPC has a register interface which the guest uses to configure it.
> + *
> + * QEMU interface:
> + * + sysbus MMIO region 0: MemoryRegion for the MPC's config registers
> + * + sysbus MMIO region 1: MemoryRegion for the upstream end of the MPC
> + * + Property "downstream": MemoryRegion defining the downstream memory
> + * + Named GPIO output "irq": set for a transaction-failed interrupt
> + */
> +
> +#ifndef TZ_MPC_H
> +#define TZ_MPC_H
> +
> +#include "hw/sysbus.h"
> +
> +#define TYPE_TZ_MPC "tz-mpc"
> +#define TZ_MPC(obj) OBJECT_CHECK(TZMPC, (obj), TYPE_TZ_MPC)
> +
> +#define TZ_NUM_PORTS 16
> +
> +#define TYPE_TZ_MPC_IOMMU_MEMORY_REGION "tz-mpc-iommu-memory-region"
> +
> +typedef struct TZMPC TZMPC;
> +
> +struct TZMPC {
> +    /*< private >*/
> +    SysBusDevice parent_obj;
> +
> +    /*< public >*/
> +
> +    qemu_irq irq;
> +
> +    /* Properties */
> +    MemoryRegion *downstream;
> +
> +    hwaddr blocksize;
> +    uint32_t blk_max;
> +
> +    /* MemoryRegions exposed to user */
> +    MemoryRegion regmr;
> +    IOMMUMemoryRegion upstream;
> +
> +    /* MemoryRegion used internally */
> +    MemoryRegion blocked_io;
> +
> +    AddressSpace downstream_as;
> +    AddressSpace blocked_io_as;
> +};
> +
> +#endif
> diff --git a/hw/misc/tz-mpc.c b/hw/misc/tz-mpc.c
> new file mode 100644
> index 0000000000..d4467ccc3b
> --- /dev/null
> +++ b/hw/misc/tz-mpc.c
> @@ -0,0 +1,381 @@
> +/*
> + * ARM TrustZone memory protection controller emulation
> + *
> + * Copyright (c) 2018 Linaro Limited
> + * Written by Peter Maydell
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 or
> + * (at your option) any later version.
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qemu/log.h"
> +#include "qapi/error.h"
> +#include "trace.h"
> +#include "hw/sysbus.h"
> +#include "hw/registerfields.h"
> +#include "hw/misc/tz-mpc.h"
> +
> +/* Our IOMMU has two IOMMU indexes, one for secure transactions and one for
> + * non-secure transactions.
> + */
> +enum {
> +    IOMMU_IDX_S,
> +    IOMMU_IDX_NS,
> +    IOMMU_NUM_INDEXES,
> +};
> +
> +/* Config registers */
> +REG32(CTRL, 0x00)
> +REG32(BLK_MAX, 0x10)
> +REG32(BLK_CFG, 0x14)
> +REG32(BLK_IDX, 0x18)
> +REG32(BLK_LUT, 0x1c)
> +REG32(INT_STAT, 0x20)
> +REG32(INT_CLEAR, 0x24)
> +REG32(INT_EN, 0x28)
> +REG32(INT_INFO1, 0x2c)
> +REG32(INT_INFO2, 0x30)
> +REG32(INT_SET, 0x34)
> +REG32(PIDR4, 0xfd0)
> +REG32(PIDR5, 0xfd4)
> +REG32(PIDR6, 0xfd8)
> +REG32(PIDR7, 0xfdc)
> +REG32(PIDR0, 0xfe0)
> +REG32(PIDR1, 0xfe4)
> +REG32(PIDR2, 0xfe8)
> +REG32(PIDR3, 0xfec)
> +REG32(CIDR0, 0xff0)
> +REG32(CIDR1, 0xff4)
> +REG32(CIDR2, 0xff8)
> +REG32(CIDR3, 0xffc)
> +
> +static const uint8_t tz_mpc_idregs[] = {
> +    0x04, 0x00, 0x00, 0x00,
> +    0x60, 0xb8, 0x1b, 0x00,
> +    0x0d, 0xf0, 0x05, 0xb1,
> +};
> +
> +static MemTxResult tz_mpc_reg_read(void *opaque, hwaddr addr,
> +                                   uint64_t *pdata,
> +                                   unsigned size, MemTxAttrs attrs)
> +{
> +    uint64_t r;
> +    uint32_t offset = addr & ~0x3;
> +
> +    switch (offset) {
> +    case A_PIDR4:
> +    case A_PIDR5:
> +    case A_PIDR6:
> +    case A_PIDR7:
> +    case A_PIDR0:
> +    case A_PIDR1:
> +    case A_PIDR2:
> +    case A_PIDR3:
> +    case A_CIDR0:
> +    case A_CIDR1:
> +    case A_CIDR2:
> +    case A_CIDR3:
> +        r = tz_mpc_idregs[(offset - A_PIDR4) / 4];
> +        break;
> +    case A_INT_CLEAR:
> +    case A_INT_SET:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "TZ MPC register read: write-only offset 0x%x\n",
> +                      offset);
> +        r = 0;
> +        break;
> +    default:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "TZ MPC register read: bad offset 0x%x\n", offset);
> +        r = 0;
> +        break;
> +    }
> +
> +    if (size != 4) {
> +        /* None of our registers are read-sensitive (except BLK_LUT,
> +         * which can special case the "size not 4" case), so just
> +         * pull the right bytes out of the word read result.
> +         */
> +        r = extract32(r, (addr & 3) * 8, size * 8);
> +    }
> +
> +    trace_tz_mpc_reg_read(addr, r, size);
> +    *pdata = r;
> +    return MEMTX_OK;
> +}
> +
> +static MemTxResult tz_mpc_reg_write(void *opaque, hwaddr addr,
> +                                    uint64_t value,
> +                                    unsigned size, MemTxAttrs attrs)
> +{
> +    uint32_t offset = addr & ~0x3;
> +
> +    trace_tz_mpc_reg_write(addr, value, size);
> +
> +    if (size != 4) {
> +        /* Expand the byte or halfword write to a full word size.
> +         * In most cases we can do this with zeroes; the exceptions
> +         * are CTRL, BLK_IDX and BLK_LUT.
> +         */
> +        uint32_t oldval;
> +
> +        switch (offset) {
> +            /* As we add support for registers which need expansions
> +             * other than zeroes we'll fill in cases here.
> +             */
> +        default:
> +            oldval = 0;
> +            break;
> +        }
> +        value = deposit32(oldval, (addr & 3) * 8, size * 8, value);
> +    }
> +
> +    switch (offset) {
> +    case A_PIDR4:
> +    case A_PIDR5:
> +    case A_PIDR6:
> +    case A_PIDR7:
> +    case A_PIDR0:
> +    case A_PIDR1:
> +    case A_PIDR2:
> +    case A_PIDR3:
> +    case A_CIDR0:
> +    case A_CIDR1:
> +    case A_CIDR2:
> +    case A_CIDR3:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "TZ MPC register write: read-only offset 0x%x\n", offset);
> +        break;
> +    default:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "TZ MPC register write: bad offset 0x%x\n", offset);
> +        break;
> +    }
> +
> +    return MEMTX_OK;
> +}
> +
> +static const MemoryRegionOps tz_mpc_reg_ops = {
> +    .read_with_attrs = tz_mpc_reg_read,
> +    .write_with_attrs = tz_mpc_reg_write,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +    .valid.min_access_size = 1,
> +    .valid.max_access_size = 4,
> +    .impl.min_access_size = 1,
> +    .impl.max_access_size = 4,
> +};
> +
> +/* Accesses only reach these read and write functions if the MPC is
> + * blocking them; non-blocked accesses go directly to the downstream
> + * memory region without passing through this code.
> + */
> +static MemTxResult tz_mpc_mem_blocked_read(void *opaque, hwaddr addr,
> +                                           uint64_t *pdata,
> +                                           unsigned size, MemTxAttrs attrs)
> +{
> +    trace_tz_mpc_mem_blocked_read(addr, size, attrs.secure);
> +
> +    *pdata = 0;
> +    return MEMTX_OK;
> +}
> +
> +static MemTxResult tz_mpc_mem_blocked_write(void *opaque, hwaddr addr,
> +                                            uint64_t value,
> +                                            unsigned size, MemTxAttrs attrs)
> +{
> +    trace_tz_mpc_mem_blocked_write(addr, value, size, attrs.secure);
> +
> +    return MEMTX_OK;
> +}
> +
> +static const MemoryRegionOps tz_mpc_mem_blocked_ops = {
> +    .read_with_attrs = tz_mpc_mem_blocked_read,
> +    .write_with_attrs = tz_mpc_mem_blocked_write,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +    .valid.min_access_size = 1,
> +    .valid.max_access_size = 8,
> +    .impl.min_access_size = 1,
> +    .impl.max_access_size = 8,
> +};
> +
> +static IOMMUTLBEntry tz_mpc_translate(IOMMUMemoryRegion *iommu,
> +                                      hwaddr addr, IOMMUAccessFlags flags,
> +                                      int iommu_idx)
> +{
> +    TZMPC *s = TZ_MPC(container_of(iommu, TZMPC, upstream));
> +    bool ok;
> +
> +    IOMMUTLBEntry ret = {
> +        .iova = addr & ~(s->blocksize - 1),
> +        .translated_addr = addr & ~(s->blocksize - 1),
> +        .addr_mask = s->blocksize - 1,
> +        .perm = IOMMU_RW,
> +    };
> +
> +    /* Look at the per-block configuration for this address, and
> +     * return a TLB entry directing the transaction at either
> +     * downstream_as or blocked_io_as, as appropriate.
> +     * For the moment, always permit accesses.
> +     */
> +    ok = true;
> +
> +    trace_tz_mpc_translate(addr, flags,
> +                           iommu_idx == IOMMU_IDX_S ? "S" : "NS",
> +                           ok ? "pass" : "block");
> +
> +    ret.target_as = ok ? &s->downstream_as : &s->blocked_io_as;
> +    return ret;
> +}
> +
> +static int tz_mpc_attrs_to_index(IOMMUMemoryRegion *iommu, MemTxAttrs attrs)
> +{
> +    /* We treat unspecified attributes like secure. Transactions with
> +     * unspecified attributes come from places like
> +     * cpu_physical_memory_write_rom() for initial image load, and we want
> +     * those to pass through the from-reset "everything is secure" config.
> +     * All the real during-emulation transactions from the CPU will
> +     * specify attributes.
> +     */
> +    return (attrs.unspecified || attrs.secure) ? IOMMU_IDX_S : IOMMU_IDX_NS;
> +}
> +
> +static int tz_mpc_num_indexes(IOMMUMemoryRegion *iommu)
> +{
> +    return IOMMU_NUM_INDEXES;
> +}
> +
> +static void tz_mpc_reset(DeviceState *dev)
> +{
> +}
> +
> +static void tz_mpc_init(Object *obj)
> +{
> +    DeviceState *dev = DEVICE(obj);
> +    TZMPC *s = TZ_MPC(obj);
> +
> +    qdev_init_gpio_out_named(dev, &s->irq, "irq", 1);
> +}
> +
> +static void tz_mpc_realize(DeviceState *dev, Error **errp)
> +{
> +    Object *obj = OBJECT(dev);
> +    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
> +    TZMPC *s = TZ_MPC(dev);
> +    uint64_t size;
> +
> +    /* We can't create the upstream end of the port until realize,
> +     * as we don't know the size of the MR used as the downstream until then.
> +     * We insist on having a downstream, to avoid complicating the code
> +     * with handling the "don't know how big this is" case. It's easy
> +     * enough for the user to create an unimplemented_device as downstream
> +     * if they have nothing else to plug into this.
> +     */
> +    if (!s->downstream) {
> +        error_setg(errp, "MPC 'downstream' link not set");
> +        return;
> +    }
> +
> +    size = memory_region_size(s->downstream);
> +
> +    memory_region_init_iommu(&s->upstream, sizeof(s->upstream),
> +                             TYPE_TZ_MPC_IOMMU_MEMORY_REGION,
> +                             obj, "tz-mpc-upstream", size);
> +
> +    /* In real hardware the block size is configurable. In QEMU we could
> +     * make it configurable but will need it to be at least as big as the
> +     * target page size so we can execute out of the resulting MRs. Guest
> +     * software is supposed to check the block size using the BLK_CFG
> +     * register, so make it fixed at the page size.
> +     */
> +    s->blocksize = memory_region_iommu_get_min_page_size(&s->upstream);
> +    if (size % s->blocksize != 0) {
> +        error_setg(errp,
> +                   "MPC 'downstream' size %" PRId64
> +                   " is not a multiple of %" HWADDR_PRIx " bytes",
> +                   size, s->blocksize);
> +        object_unref(OBJECT(&s->upstream));
> +        return;
> +    }
> +
> +    /* BLK_MAX is the max value of BLK_IDX, which indexes an array of 32-bit
> +     * words, each bit of which indicates one block.
> +     */
> +    s->blk_max = DIV_ROUND_UP(size / s->blocksize, 32);
> +
> +    memory_region_init_io(&s->regmr, obj, &tz_mpc_reg_ops,
> +                          s, "tz-mpc-regs", 0x1000);
> +    sysbus_init_mmio(sbd, &s->regmr);
> +
> +    sysbus_init_mmio(sbd, MEMORY_REGION(&s->upstream));
> +
> +    /* This memory region is not exposed to users of this device as a
> +     * sysbus MMIO region, but is instead used internally as something
> +     * that our IOMMU translate function might direct accesses to.
> +     */
> +    memory_region_init_io(&s->blocked_io, obj, &tz_mpc_mem_blocked_ops,
> +                          s, "tz-mpc-blocked-io", size);
> +
> +    address_space_init(&s->downstream_as, s->downstream,
> +                       "tz-mpc-downstream");
> +    address_space_init(&s->blocked_io_as, &s->blocked_io,
> +                       "tz-mpc-blocked-io");
> +}
> +
> +static const VMStateDescription tz_mpc_vmstate = {
> +    .name = "tz-mpc",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +static Property tz_mpc_properties[] = {
> +    DEFINE_PROP_LINK("downstream", TZMPC, downstream,
> +                     TYPE_MEMORY_REGION, MemoryRegion *),
> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
> +static void tz_mpc_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    dc->realize = tz_mpc_realize;
> +    dc->vmsd = &tz_mpc_vmstate;
> +    dc->reset = tz_mpc_reset;
> +    dc->props = tz_mpc_properties;
> +}
> +
> +static const TypeInfo tz_mpc_info = {
> +    .name = TYPE_TZ_MPC,
> +    .parent = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(TZMPC),
> +    .instance_init = tz_mpc_init,
> +    .class_init = tz_mpc_class_init,
> +};
> +
> +static void tz_mpc_iommu_memory_region_class_init(ObjectClass *klass,
> +                                                  void *data)
> +{
> +    IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass);
> +
> +    imrc->translate = tz_mpc_translate;
> +    imrc->attrs_to_index = tz_mpc_attrs_to_index;
> +    imrc->num_indexes = tz_mpc_num_indexes;
> +}
> +
> +static const TypeInfo tz_mpc_iommu_memory_region_info = {
> +    .name = TYPE_TZ_MPC_IOMMU_MEMORY_REGION,
> +    .parent = TYPE_IOMMU_MEMORY_REGION,
> +    .class_init = tz_mpc_iommu_memory_region_class_init,
> +};
> +
> +static void tz_mpc_register_types(void)
> +{
> +    type_register_static(&tz_mpc_info);
> +    type_register_static(&tz_mpc_iommu_memory_region_info);
> +}
> +
> +type_init(tz_mpc_register_types);
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 1823f900b9..9cddb699df 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -449,6 +449,8 @@ F: hw/char/cmsdk-apb-uart.c
>  F: include/hw/char/cmsdk-apb-uart.h
>  F: hw/misc/tz-ppc.c
>  F: include/hw/misc/tz-ppc.h
> +F: hw/misc/tz-mpc.c
> +F: include/hw/misc/tz-mpc.h
>  
>  ARM cores
>  M: Peter Maydell <peter.maydell@linaro.org>
> diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
> index dd29e741c2..30e73847ac 100644
> --- a/default-configs/arm-softmmu.mak
> +++ b/default-configs/arm-softmmu.mak
> @@ -106,6 +106,7 @@ CONFIG_CMSDK_APB_UART=y
>  CONFIG_MPS2_FPGAIO=y
>  CONFIG_MPS2_SCC=y
>  
> +CONFIG_TZ_MPC=y
>  CONFIG_TZ_PPC=y
>  CONFIG_IOTKIT=y
>  CONFIG_IOTKIT_SECCTL=y
> diff --git a/hw/misc/trace-events b/hw/misc/trace-events
> index 562d9ed005..d4835c8970 100644
> --- a/hw/misc/trace-events
> +++ b/hw/misc/trace-events
> @@ -84,6 +84,13 @@ mos6522_set_sr_int(void) "set sr_int"
>  mos6522_write(uint64_t addr, uint64_t val) "reg=0x%"PRIx64 " val=0x%"PRIx64
>  mos6522_read(uint64_t addr, unsigned val) "reg=0x%"PRIx64 " val=0x%x"
>  
> +# hw/misc/tz-mpc.c
> +tz_mpc_reg_read(uint32_t offset, uint64_t data, unsigned size) "TZ MPC regs read: offset 0x%x data 0x%" PRIx64 " size %u"
> +tz_mpc_reg_write(uint32_t offset, uint64_t data, unsigned size) "TZ MPC regs write: offset 0x%x data 0x%" PRIx64 " size %u"
> +tz_mpc_mem_blocked_read(uint64_t addr, unsigned size, bool secure) "TZ MPC blocked read: offset 0x%" PRIx64 " size %u secure %d"
> +tz_mpc_mem_blocked_write(uint64_t addr, uint64_t data, unsigned size, bool secure) "TZ MPC blocked write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d"
> +tz_mpc_translate(uint64_t addr, int flags, const char *idx, const char *res) "TZ MPC translate: addr 0x%" PRIx64 " flags 0x%x iommu_idx %s: %s"
> +
>  # hw/misc/tz-ppc.c
>  tz_ppc_reset(void) "TZ PPC: reset"
>  tz_ppc_cfg_nonsec(int n, int level) "TZ PPC: cfg_nonsec[%d] = %d"
> 

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 01/27] memory.h: Improve IOMMU related documentation
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 01/27] memory.h: Improve IOMMU related documentation Peter Maydell
  2018-05-21 19:46   ` Richard Henderson
  2018-05-22  9:16   ` Alex Bennée
@ 2018-05-22 11:40   ` Auger Eric
  2 siblings, 0 replies; 114+ messages in thread
From: Auger Eric @ 2018-05-22 11:40 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel
  Cc: Paolo Bonzini, Richard Henderson, Alex Bennée, patches

Hi Peter,

On 05/21/2018 04:03 PM, Peter Maydell wrote:
> Add more detail to the documentation for memory_region_init_iommu()
> and other IOMMU-related functions and data structures.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Eric Auger <eric.auger@redhat.com>

Thanks

Eric
> ---
> v2->v3 changes:
>  * minor wording tweaks per Eric's review
>  * moved the bit about requirements to notify out from the translate
>    method docs to the top level class doc comment
>  * added description of flags argument and in particular that it's
>    just an optimization and callers can pass IOMMU_NONE to get the
>    full permissions
> v1 -> v2 changes:
>  * documented replay method
>  * added note about wanting RCU or big qemu lock while calling
>    translate
> ---
>  include/exec/memory.h | 105 ++++++++++++++++++++++++++++++++++++++----
>  1 file changed, 95 insertions(+), 10 deletions(-)
> 
> diff --git a/include/exec/memory.h b/include/exec/memory.h
> index 4fa1227f13..cce355d2d8 100644
> --- a/include/exec/memory.h
> +++ b/include/exec/memory.h
> @@ -194,29 +194,100 @@ enum IOMMUMemoryRegionAttr {
>      IOMMU_ATTR_SPAPR_TCE_FD
>  };
>  
> +/**
> + * IOMMUMemoryRegionClass:
> + *
> + * All IOMMU implementations need to subclass TYPE_IOMMU_MEMORY_REGION
> + * and provide an implementation of at least the @translate method here
> + * to handle requests to the memory region. Other methods are optional.
> + *
> + * The IOMMU implementation must use the IOMMU notifier infrastructure
> + * to report whenever mappings are changed, by calling
> + * memory_region_notify_iommu() (or, if necessary, by calling
> + * memory_region_notify_one() for each registered notifier).
> + */
>  typedef struct IOMMUMemoryRegionClass {
>      /* private */
>      struct DeviceClass parent_class;
>  
>      /*
> -     * Return a TLB entry that contains a given address. Flag should
> -     * be the access permission of this translation operation. We can
> -     * set flag to IOMMU_NONE to mean that we don't need any
> -     * read/write permission checks, like, when for region replay.
> +     * Return a TLB entry that contains a given address.
> +     *
> +     * The IOMMUAccessFlags indicated via @flag are optional and may
> +     * be specified as IOMMU_NONE to indicate that the caller needs
> +     * the full translation information for both reads and writes. If
> +     * the access flags are specified then the IOMMU implementation
> +     * may use this as an optimization, to stop doing a page table
> +     * walk as soon as it knows that the requested permissions are not
> +     * allowed. If IOMMU_NONE is passed then the IOMMU must do the
> +     * full page table walk and report the permissions in the returned
> +     * IOMMUTLBEntry. (Note that this implies that an IOMMU may not
> +     * return different mappings for reads and writes.)
> +     *
> +     * The returned information remains valid while the caller is
> +     * holding the big QEMU lock or is inside an RCU critical section;
> +     * if the caller wishes to cache the mapping beyond that it must
> +     * register an IOMMU notifier so it can invalidate its cached
> +     * information when the IOMMU mapping changes.
> +     *
> +     * @iommu: the IOMMUMemoryRegion
> +     * @hwaddr: address to be translated within the memory region
> +     * @flag: requested access permissions
>       */
>      IOMMUTLBEntry (*translate)(IOMMUMemoryRegion *iommu, hwaddr addr,
>                                 IOMMUAccessFlags flag);
> -    /* Returns minimum supported page size */
> +    /* Returns minimum supported page size in bytes.
> +     * If this method is not provided then the minimum is assumed to
> +     * be TARGET_PAGE_SIZE.
> +     *
> +     * @iommu: the IOMMUMemoryRegion
> +     */
>      uint64_t (*get_min_page_size)(IOMMUMemoryRegion *iommu);
> -    /* Called when IOMMU Notifier flag changed */
> +    /* Called when IOMMU Notifier flag changes (ie when the set of
> +     * events which IOMMU users are requesting notification for changes).
> +     * Optional method -- need not be provided if the IOMMU does not
> +     * need to know exactly which events must be notified.
> +     *
> +     * @iommu: the IOMMUMemoryRegion
> +     * @old_flags: events which previously needed to be notified
> +     * @new_flags: events which now need to be notified
> +     */
>      void (*notify_flag_changed)(IOMMUMemoryRegion *iommu,
>                                  IOMMUNotifierFlag old_flags,
>                                  IOMMUNotifierFlag new_flags);
> -    /* Set this up to provide customized IOMMU replay function */
> +    /* Called to handle memory_region_iommu_replay().
> +     *
> +     * The default implementation of memory_region_iommu_replay() is to
> +     * call the IOMMU translate method for every page in the address space
> +     * with flag == IOMMU_NONE and then call the notifier if translate
> +     * returns a valid mapping. If this method is implemented then it
> +     * overrides the default behaviour, and must provide the full semantics
> +     * of memory_region_iommu_replay(), by calling @notifier for every
> +     * translation present in the IOMMU.
> +     *
> +     * Optional method -- an IOMMU only needs to provide this method
> +     * if the default is inefficient or produces undesirable side effects.
> +     *
> +     * Note: this is not related to record-and-replay functionality.
> +     */
>      void (*replay)(IOMMUMemoryRegion *iommu, IOMMUNotifier *notifier);
>  
> -    /* Get IOMMU misc attributes */
> -    int (*get_attr)(IOMMUMemoryRegion *iommu, enum IOMMUMemoryRegionAttr,
> +    /* Get IOMMU misc attributes. This is an optional method that
> +     * can be used to allow users of the IOMMU to get implementation-specific
> +     * information. The IOMMU implements this method to handle calls
> +     * by IOMMU users to memory_region_iommu_get_attr() by filling in
> +     * the arbitrary data pointer for any IOMMUMemoryRegionAttr values that
> +     * the IOMMU supports. If the method is unimplemented then
> +     * memory_region_iommu_get_attr() will always return -EINVAL.
> +     *
> +     * @iommu: the IOMMUMemoryRegion
> +     * @attr: attribute being queried
> +     * @data: memory to fill in with the attribute data
> +     *
> +     * Returns 0 on success, or a negative errno; in particular
> +     * returns -EINVAL for unrecognized or unimplemented attribute types.
> +     */
> +    int (*get_attr)(IOMMUMemoryRegion *iommu, enum IOMMUMemoryRegionAttr attr,
>                      void *data);
>  } IOMMUMemoryRegionClass;
>  
> @@ -705,6 +776,14 @@ static inline void memory_region_init_reservation(MemoryRegion *mr,
>   * An IOMMU region translates addresses and forwards accesses to a target
>   * memory region.
>   *
> + * The IOMMU implementation must define a subclass of TYPE_IOMMU_MEMORY_REGION.
> + * @_iommu_mr should be a pointer to enough memory for an instance of
> + * that subclass, @instance_size is the size of that subclass, and
> + * @mrtypename is its name. This function will initialize @_iommu_mr as an
> + * instance of the subclass, and its methods will then be called to handle
> + * accesses to the memory region. See the documentation of
> + * #IOMMUMemoryRegionClass for further details.
> + *
>   * @_iommu_mr: the #IOMMUMemoryRegion to be initialized
>   * @instance_size: the IOMMUMemoryRegion subclass instance size
>   * @mrtypename: the type name of the #IOMMUMemoryRegion
> @@ -953,6 +1032,8 @@ void memory_region_register_iommu_notifier(MemoryRegion *mr,
>   * a notifier with the minimum page granularity returned by
>   * mr->iommu_ops->get_page_size().
>   *
> + * Note: this is not related to record-and-replay functionality.
> + *
>   * @iommu_mr: the memory region to observe
>   * @n: the notifier to which to replay iommu mappings
>   */
> @@ -962,6 +1043,8 @@ void memory_region_iommu_replay(IOMMUMemoryRegion *iommu_mr, IOMMUNotifier *n);
>   * memory_region_iommu_replay_all: replay existing IOMMU translations
>   * to all the notifiers registered.
>   *
> + * Note: this is not related to record-and-replay functionality.
> + *
>   * @iommu_mr: the memory region to observe
>   */
>  void memory_region_iommu_replay_all(IOMMUMemoryRegion *iommu_mr);
> @@ -981,7 +1064,9 @@ void memory_region_unregister_iommu_notifier(MemoryRegion *mr,
>   * memory_region_iommu_get_attr: return an IOMMU attr if get_attr() is
>   * defined on the IOMMU.
>   *
> - * Returns 0 if succeded, error code otherwise.
> + * Returns 0 on success, or a negative errno otherwise. In particular,
> + * -EINVAL indicates that the IOMMU does not support the requested
> + * attribute.
>   *
>   * @iommu_mr: the memory region
>   * @attr: the requested attribute
> 

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 18/27] hw/misc/tz-mpc.c: Implement the Arm TrustZone Memory Protection Controller
  2018-05-22 11:30   ` Auger Eric
@ 2018-05-22 11:56     ` Peter Maydell
  2018-05-22 12:23       ` Auger Eric
  0 siblings, 1 reply; 114+ messages in thread
From: Peter Maydell @ 2018-05-22 11:56 UTC (permalink / raw)
  To: Auger Eric
  Cc: qemu-arm, QEMU Developers, Paolo Bonzini, Richard Henderson,
	Alex Bennée, patches

On 22 May 2018 at 12:30, Auger Eric <eric.auger@redhat.com> wrote:
> Hi Peter,
>
> On 05/21/2018 04:03 PM, Peter Maydell wrote:
>> Implement the Arm TrustZone Memory Protection Controller, which sits
>> in front of RAM and allows secure software to configure it to either
>> pass through or reject transactions.
>>
>> We implement the MPC as a QEMU IOMMU, which will direct transactions
>> either through to the devices and memory behind it or to a special
>> "never works" AddressSpace if they are blocked.
>>
>> This initial commit implements the skeleton of the device:
>>  * it always permits accesses
>>  * it doesn't implement most of the registers
>>  * it doesn't implement the interrupt or other behaviour
>>    for blocked transactions
>>
>> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
>
> this patch does not seem to apply on master.

Clash in the MAINTAINERS file? There's a dependency on another
MAINTAINERS patch, see the Based-on: line in the cover letter.

thanks
-- PMM

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 18/27] hw/misc/tz-mpc.c: Implement the Arm TrustZone Memory Protection Controller
  2018-05-22 11:56     ` Peter Maydell
@ 2018-05-22 12:23       ` Auger Eric
  0 siblings, 0 replies; 114+ messages in thread
From: Auger Eric @ 2018-05-22 12:23 UTC (permalink / raw)
  To: Peter Maydell
  Cc: patches, QEMU Developers, qemu-arm, Paolo Bonzini,
	Alex Bennée, Richard Henderson

Hi Peter,

On 05/22/2018 01:56 PM, Peter Maydell wrote:
> On 22 May 2018 at 12:30, Auger Eric <eric.auger@redhat.com> wrote:
>> Hi Peter,
>>
>> On 05/21/2018 04:03 PM, Peter Maydell wrote:
>>> Implement the Arm TrustZone Memory Protection Controller, which sits
>>> in front of RAM and allows secure software to configure it to either
>>> pass through or reject transactions.
>>>
>>> We implement the MPC as a QEMU IOMMU, which will direct transactions
>>> either through to the devices and memory behind it or to a special
>>> "never works" AddressSpace if they are blocked.
>>>
>>> This initial commit implements the skeleton of the device:
>>>  * it always permits accesses
>>>  * it doesn't implement most of the registers
>>>  * it doesn't implement the interrupt or other behaviour
>>>    for blocked transactions
>>>
>>> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
>>
>> this patch does not seem to apply on master.
> 
> Clash in the MAINTAINERS file? There's a dependency on another
> MAINTAINERS patch, see the Based-on: line in the cover letter.

Ah OK.

Thanks

Eric
> 
> thanks
> -- PMM
> 

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 14/27] iommu: Add IOMMU index concept to IOMMU API
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 14/27] iommu: Add IOMMU index concept to IOMMU API Peter Maydell
  2018-05-22  3:03   ` Peter Xu
@ 2018-05-22 12:58   ` Auger Eric
  2018-05-22 13:22     ` Peter Maydell
  2018-05-22 17:42   ` Richard Henderson
  2 siblings, 1 reply; 114+ messages in thread
From: Auger Eric @ 2018-05-22 12:58 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel
  Cc: Paolo Bonzini, Richard Henderson, Alex Bennée, patches

Hi Peter,
On 05/21/2018 04:03 PM, Peter Maydell wrote:
> If an IOMMU supports mappings that care about the memory
> transaction attributes, then it no longer has a unique
> address -> output mapping, but more than one. We can
> represent these using an IOMMU index, analogous to TCG's
> mmu indexes.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  include/exec/memory.h | 52 +++++++++++++++++++++++++++++++++++++++++++
>  memory.c              | 23 +++++++++++++++++++
>  2 files changed, 75 insertions(+)
> 
> diff --git a/include/exec/memory.h b/include/exec/memory.h
> index 309fdfb89b..f6226fb263 100644
> --- a/include/exec/memory.h
> +++ b/include/exec/memory.h
> @@ -206,6 +206,20 @@ enum IOMMUMemoryRegionAttr {
>   * to report whenever mappings are changed, by calling
>   * memory_region_notify_iommu() (or, if necessary, by calling
>   * memory_region_notify_one() for each registered notifier).
> + *
> + * Conceptually an IOMMU provides a mapping from input address
> + * to an output TLB entry.
actually it takes a source identifier too (ARM streamid + substreamID,
this latter is not yet supported).
At the moment we have 1 IOMMUMRRegion per sid on ARM. For each
IOMMUMRRegion we would now have 2 indexes (1 for secure and 1 for
unsecure). How do you see the implementation of PASIDs (substreamids).
Would that be based on indexes or not?
 If the IOMMU is aware of memory transaction
> + * attributes and the output TLB entry depends on the transaction
> + * attributes, we represent this using IOMMU indexes. Each index
> + * selects a particular translation table that the IOMMU has:
> + *   @attrs_to_index returns the IOMMU index for a set of transaction attributes
> + *   @translate takes an input address and an IOMMU index
> + * and the mapping returned can only depend on the input address and the
> + * IOMMU index.
> + *
> + * Most IOMMUs don't care about the transaction attributes and support
> + * only a single IOMMU index. A more complex IOMMU might have one index
> + * for secure transactions and one for non-secure transactions.
>   */
>  typedef struct IOMMUMemoryRegionClass {
>      /* private */
> @@ -290,6 +304,26 @@ typedef struct IOMMUMemoryRegionClass {
>       */
>      int (*get_attr)(IOMMUMemoryRegion *iommu, enum IOMMUMemoryRegionAttr attr,
>                      void *data);
> +
> +    /* Return the IOMMU index to use for a given set of transaction attributes.
> +     *
> +     * Optional method: if an IOMMU only supports a single IOMMU index then
> +     * the default implementation of memory_region_iommu_attrs_to_index()
> +     * will return 0.
> +     *
> +     * The indexes supported by an IOMMU must be contiguous, starting at 0.
> +     *
> +     * @iommu: the IOMMUMemoryRegion
> +     * @attrs: memory transaction attributes
> +     */
> +    int (*attrs_to_index)(IOMMUMemoryRegion *iommu, MemTxAttrs attrs);
> +
> +    /* Return the number of IOMMU indexes this IOMMU supports.
> +     *
> +     * Optional method: if this method is not provided, then
> +     * memory_region_iommu_num_indexes() will return 1, indicating that
> +     * only a single IOMMU index is supported.
> +     */
>  } IOMMUMemoryRegionClass;
>  
>  typedef struct CoalescedMemoryRange CoalescedMemoryRange;
> @@ -1077,6 +1111,24 @@ int memory_region_iommu_get_attr(IOMMUMemoryRegion *iommu_mr,
>                                   enum IOMMUMemoryRegionAttr attr,
>                                   void *data);
>  
> +/**
> + * memory_region_iommu_attrs_to_index: return the IOMMU index to
> + * use for translations with the given memory transaction attributes.
> + *
> + * @iommu_mr: the memory region
> + * @attrs: the memory transaction attributes
> + */
> +int memory_region_iommu_attrs_to_index(IOMMUMemoryRegion *iommu_mr,
> +                                       MemTxAttrs attrs);
> +
> +/**
> + * memory_region_iommu_num_indexes: return the total number of IOMMU
> + * indexes that this IOMMU supports.
is it IOMMU wide characteristics or per IOMMUMRRegion (SID)?

Thanks

Eric
> + *
> + * @iommu_mr: the memory region
> + */
> +int memory_region_iommu_num_indexes(IOMMUMemoryRegion *iommu_mr);
> +
>  /**
>   * memory_region_name: get a memory region's name
>   *
> diff --git a/memory.c b/memory.c
> index 10fa2ddd31..07d5fa7862 100644
> --- a/memory.c
> +++ b/memory.c
> @@ -1918,6 +1918,29 @@ int memory_region_iommu_get_attr(IOMMUMemoryRegion *iommu_mr,
>      return imrc->get_attr(iommu_mr, attr, data);
>  }
>  
> +int memory_region_iommu_attrs_to_index(IOMMUMemoryRegion *iommu_mr,
> +                                       MemTxAttrs attrs)
> +{
> +    IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_GET_CLASS(iommu_mr);
> +
> +    if (!imrc->attrs_to_index) {
> +        return 0;
> +    }
> +
> +    return imrc->attrs_to_index(iommu_mr, attrs);
> +}
> +
> +int memory_region_iommu_num_indexes(IOMMUMemoryRegion *iommu_mr)
> +{
> +    IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_GET_CLASS(iommu_mr);
> +
> +    if (!imrc->num_indexes) {
> +        return 1;
> +    }
> +
> +    return imrc->num_indexes(iommu_mr);
> +}
> +
>  void memory_region_set_log(MemoryRegion *mr, bool log, unsigned client)
>  {
>      uint8_t mask = 1 << client;
> 

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 14/27] iommu: Add IOMMU index concept to IOMMU API
  2018-05-22 12:58   ` Auger Eric
@ 2018-05-22 13:22     ` Peter Maydell
  2018-05-22 14:11       ` Auger Eric
  0 siblings, 1 reply; 114+ messages in thread
From: Peter Maydell @ 2018-05-22 13:22 UTC (permalink / raw)
  To: Auger Eric
  Cc: qemu-arm, QEMU Developers, Paolo Bonzini, Richard Henderson,
	Alex Bennée, patches

On 22 May 2018 at 13:58, Auger Eric <eric.auger@redhat.com> wrote:
> Hi Peter,
> On 05/21/2018 04:03 PM, Peter Maydell wrote:
>> If an IOMMU supports mappings that care about the memory
>> transaction attributes, then it no longer has a unique
>> address -> output mapping, but more than one. We can
>> represent these using an IOMMU index, analogous to TCG's
>> mmu indexes.
>>
>> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
>> ---
>>  include/exec/memory.h | 52 +++++++++++++++++++++++++++++++++++++++++++
>>  memory.c              | 23 +++++++++++++++++++
>>  2 files changed, 75 insertions(+)
>>
>> diff --git a/include/exec/memory.h b/include/exec/memory.h
>> index 309fdfb89b..f6226fb263 100644
>> --- a/include/exec/memory.h
>> +++ b/include/exec/memory.h
>> @@ -206,6 +206,20 @@ enum IOMMUMemoryRegionAttr {
>>   * to report whenever mappings are changed, by calling
>>   * memory_region_notify_iommu() (or, if necessary, by calling
>>   * memory_region_notify_one() for each registered notifier).
>> + *
>> + * Conceptually an IOMMU provides a mapping from input address
>> + * to an output TLB entry.
> actually it takes a source identifier too (ARM streamid + substreamID,
> this latter is not yet supported).
> At the moment we have 1 IOMMUMRRegion per sid on ARM. For each
> IOMMUMRRegion we would now have 2 indexes (1 for secure and 1 for
> unsecure). How do you see the implementation of PASIDs (substreamids).
> Would that be based on indexes or not?

Good question. I guess we would set that up so that the
substream ID is in the memory transaction attributes as the
requester_id and then use that as part of the IOMMU index ?
Or you could use the indirection between tx attrs and indexes
to allow you to map down a potentially large space of substream
ID values to a smaller set of actually different configurations.

How many substream IDs do we expect to see in practice?

>> +/**
>> + * memory_region_iommu_attrs_to_index: return the IOMMU index to
>> + * use for translations with the given memory transaction attributes.
>> + *
>> + * @iommu_mr: the memory region
>> + * @attrs: the memory transaction attributes
>> + */
>> +int memory_region_iommu_attrs_to_index(IOMMUMemoryRegion *iommu_mr,
>> +                                       MemTxAttrs attrs);
>> +
>> +/**
>> + * memory_region_iommu_num_indexes: return the total number of IOMMU
>> + * indexes that this IOMMU supports.
> is it IOMMU wide characteristics or per IOMMUMRRegion (SID)?

I generally in this API document have been treating "IOMMU" and
"IOMMURegion" as synonymous, since from the perspective of the API
we don't care whether there's a bigger underlying thing in common
between IOMMURegions.

thanks
-- PMM

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 14/27] iommu: Add IOMMU index concept to IOMMU API
  2018-05-22 13:22     ` Peter Maydell
@ 2018-05-22 14:11       ` Auger Eric
  2018-05-22 14:19         ` Peter Maydell
  0 siblings, 1 reply; 114+ messages in thread
From: Auger Eric @ 2018-05-22 14:11 UTC (permalink / raw)
  To: Peter Maydell
  Cc: patches, QEMU Developers, qemu-arm, Paolo Bonzini,
	Alex Bennée, Richard Henderson

Hi Peter,

On 05/22/2018 03:22 PM, Peter Maydell wrote:
> On 22 May 2018 at 13:58, Auger Eric <eric.auger@redhat.com> wrote:
>> Hi Peter,
>> On 05/21/2018 04:03 PM, Peter Maydell wrote:
>>> If an IOMMU supports mappings that care about the memory
>>> transaction attributes, then it no longer has a unique
>>> address -> output mapping, but more than one. We can
>>> represent these using an IOMMU index, analogous to TCG's
>>> mmu indexes.
>>>
>>> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
>>> ---
>>>  include/exec/memory.h | 52 +++++++++++++++++++++++++++++++++++++++++++
>>>  memory.c              | 23 +++++++++++++++++++
>>>  2 files changed, 75 insertions(+)
>>>
>>> diff --git a/include/exec/memory.h b/include/exec/memory.h
>>> index 309fdfb89b..f6226fb263 100644
>>> --- a/include/exec/memory.h
>>> +++ b/include/exec/memory.h
>>> @@ -206,6 +206,20 @@ enum IOMMUMemoryRegionAttr {
>>>   * to report whenever mappings are changed, by calling
>>>   * memory_region_notify_iommu() (or, if necessary, by calling
>>>   * memory_region_notify_one() for each registered notifier).
>>> + *
>>> + * Conceptually an IOMMU provides a mapping from input address
>>> + * to an output TLB entry.
>> actually it takes a source identifier too (ARM streamid + substreamID,
>> this latter is not yet supported).
>> At the moment we have 1 IOMMUMRRegion per sid on ARM. For each
>> IOMMUMRRegion we would now have 2 indexes (1 for secure and 1 for
>> unsecure). How do you see the implementation of PASIDs (substreamids).
>> Would that be based on indexes or not?
> 
> Good question. I guess we would set that up so that the
> substream ID is in the memory transaction attributes as the
> requester_id and then use that as part of the IOMMU index ?
> Or you could use the indirection between tx attrs and indexes
> to allow you to map down a potentially large space of substream
> ID values to a smaller set of actually different configurations.
> 
> How many substream IDs do we expect to see in practice?

Spec says max 20 bits, matching the max size of the PASID

Thanks

Eric

> 
>>> +/**
>>> + * memory_region_iommu_attrs_to_index: return the IOMMU index to
>>> + * use for translations with the given memory transaction attributes.
>>> + *
>>> + * @iommu_mr: the memory region
>>> + * @attrs: the memory transaction attributes
>>> + */
>>> +int memory_region_iommu_attrs_to_index(IOMMUMemoryRegion *iommu_mr,
>>> +                                       MemTxAttrs attrs);
>>> +
>>> +/**
>>> + * memory_region_iommu_num_indexes: return the total number of IOMMU
>>> + * indexes that this IOMMU supports.
>> is it IOMMU wide characteristics or per IOMMUMRRegion (SID)?
> 
> I generally in this API document have been treating "IOMMU" and
> "IOMMURegion" as synonymous, since from the perspective of the API
> we don't care whether there's a bigger underlying thing in common
> between IOMMURegions.
> 
> thanks
> -- PMM
> 

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 14/27] iommu: Add IOMMU index concept to IOMMU API
  2018-05-22 14:11       ` Auger Eric
@ 2018-05-22 14:19         ` Peter Maydell
  2018-05-22 14:22           ` Auger Eric
  0 siblings, 1 reply; 114+ messages in thread
From: Peter Maydell @ 2018-05-22 14:19 UTC (permalink / raw)
  To: Auger Eric
  Cc: patches, QEMU Developers, qemu-arm, Paolo Bonzini,
	Alex Bennée, Richard Henderson

On 22 May 2018 at 15:11, Auger Eric <eric.auger@redhat.com> wrote:
> Hi Peter,
>
> On 05/22/2018 03:22 PM, Peter Maydell wrote:
>> How many substream IDs do we expect to see in practice?
>
> Spec says max 20 bits, matching the max size of the PASID

Right, but do we actually expect to see transactions from
devices that use the whole 2^20 possible values, or will
they in practice mostly use 1..5, or somethnig else?

thanks
-- PMM

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 14/27] iommu: Add IOMMU index concept to IOMMU API
  2018-05-22 14:19         ` Peter Maydell
@ 2018-05-22 14:22           ` Auger Eric
  0 siblings, 0 replies; 114+ messages in thread
From: Auger Eric @ 2018-05-22 14:22 UTC (permalink / raw)
  To: Peter Maydell
  Cc: patches, QEMU Developers, qemu-arm, Paolo Bonzini,
	Alex Bennée, Richard Henderson



On 05/22/2018 04:19 PM, Peter Maydell wrote:
> On 22 May 2018 at 15:11, Auger Eric <eric.auger@redhat.com> wrote:
>> Hi Peter,
>>
>> On 05/22/2018 03:22 PM, Peter Maydell wrote:
>>> How many substream IDs do we expect to see in practice?
>>
>> Spec says max 20 bits, matching the max size of the PASID
> 
> Right, but do we actually expect to see transactions from
> devices that use the whole 2^20 possible values, or will
> they in practice mostly use 1..5, or somethnig else?

An example given in the spec mentions 8.

"An example would be a compute accelerator with 8 contexts that might
each map to a different user process, but where the single device has
common configuration meaning it must be assigned to a VM whole."

Thanks

Eric
> 
> thanks
> -- PMM
> 

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 03/27] Make address_space_translate{, _cached}() take a MemTxAttrs argument
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 03/27] Make address_space_translate{, _cached}() " Peter Maydell
  2018-05-22 10:49   ` Alex Bennée
@ 2018-05-22 16:12   ` Richard Henderson
  1 sibling, 0 replies; 114+ messages in thread
From: Richard Henderson @ 2018-05-22 16:12 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel
  Cc: patches, Paolo Bonzini, Alex Bennée

On 05/21/2018 07:03 AM, Peter Maydell wrote:
> As part of plumbing MemTxAttrs down to the IOMMU translate method,
> add MemTxAttrs as an argument to address_space_translate()
> and address_space_translate_cached(). Callers either have an
> attrs value to hand, or don't care and can use MEMTXATTRS_UNSPECIFIED.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 04/27] Make address_space_map() take a MemTxAttrs argument
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 04/27] Make address_space_map() " Peter Maydell
  2018-05-22 10:49   ` Alex Bennée
@ 2018-05-22 16:13   ` Richard Henderson
  1 sibling, 0 replies; 114+ messages in thread
From: Richard Henderson @ 2018-05-22 16:13 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel
  Cc: patches, Paolo Bonzini, Alex Bennée

On 05/21/2018 07:03 AM, Peter Maydell wrote:
> As part of plumbing MemTxAttrs down to the IOMMU translate method,
> add MemTxAttrs as an argument to address_space_map().
> Its callers either have an attrs value to hand, or don't care
> and can use MEMTXATTRS_UNSPECIFIED.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 05/27] Make address_space_access_valid() take a MemTxAttrs argument
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 05/27] Make address_space_access_valid() " Peter Maydell
  2018-05-22 10:50   ` Alex Bennée
@ 2018-05-22 16:14   ` Richard Henderson
  1 sibling, 0 replies; 114+ messages in thread
From: Richard Henderson @ 2018-05-22 16:14 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel
  Cc: patches, Paolo Bonzini, Alex Bennée

On 05/21/2018 07:03 AM, Peter Maydell wrote:
> As part of plumbing MemTxAttrs down to the IOMMU translate method,
> add MemTxAttrs as an argument to address_space_access_valid().
> Its callers either have an attrs value to hand, or don't care
> and can use MEMTXATTRS_UNSPECIFIED.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 06/27] Make flatview_extend_translation() take a MemTxAttrs argument
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 06/27] Make flatview_extend_translation() " Peter Maydell
  2018-05-22 10:56   ` Alex Bennée
@ 2018-05-22 16:15   ` Richard Henderson
  1 sibling, 0 replies; 114+ messages in thread
From: Richard Henderson @ 2018-05-22 16:15 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel
  Cc: patches, Paolo Bonzini, Alex Bennée

On 05/21/2018 07:03 AM, Peter Maydell wrote:
> As part of plumbing MemTxAttrs down to the IOMMU translate method,
> add MemTxAttrs as an argument to flatview_extend_translation().
> Its callers either have an attrs value to hand, or don't care
> and can use MEMTXATTRS_UNSPECIFIED.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 07/27] Make memory_region_access_valid() take a MemTxAttrs argument
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 07/27] Make memory_region_access_valid() " Peter Maydell
  2018-05-22 10:57   ` Alex Bennée
@ 2018-05-22 16:17   ` Richard Henderson
  1 sibling, 0 replies; 114+ messages in thread
From: Richard Henderson @ 2018-05-22 16:17 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel
  Cc: patches, Paolo Bonzini, Alex Bennée

On 05/21/2018 07:03 AM, Peter Maydell wrote:
> As part of plumbing MemTxAttrs down to the IOMMU translate method,
> add MemTxAttrs as an argument to memory_region_access_valid().
> Its callers either have an attrs value to hand, or don't care
> and can use MEMTXATTRS_UNSPECIFIED.
> 
> The callsite in flatview_access_valid() is part of a recursive
> loop flatview_access_valid() -> memory_region_access_valid() ->
>  subpage_accepts() -> flatview_access_valid(); we make it pass
> MEMTXATTRS_UNSPECIFIED for now, until the next several commits
> have plumbed an attrs parameter through the rest of the loop
> and we can add an attrs parameter to flatview_access_valid().
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 08/27] Make MemoryRegion valid.accepts callback take a MemTxAttrs argument
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 08/27] Make MemoryRegion valid.accepts callback " Peter Maydell
  2018-05-22 10:58   ` Alex Bennée
@ 2018-05-22 16:20   ` Richard Henderson
  1 sibling, 0 replies; 114+ messages in thread
From: Richard Henderson @ 2018-05-22 16:20 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel
  Cc: patches, Paolo Bonzini, Alex Bennée

On 05/21/2018 07:03 AM, Peter Maydell wrote:
> As part of plumbing MemTxAttrs down to the IOMMU translate method,
> add MemTxAttrs as an argument to the MemoryRegion valid.accepts
> callback. We'll need this for subpage_accepts().
> 
> We could take the approach we used with the read and write
> callbacks and add new a new _with_attrs version, but since there
> are so few implementations of the accepts hook we just change
> them all.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 09/27] Make flatview_access_valid() take a MemTxAttrs argument
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 09/27] Make flatview_access_valid() " Peter Maydell
  2018-05-22 10:58   ` Alex Bennée
@ 2018-05-22 16:33   ` Richard Henderson
  2018-05-22 16:37     ` Peter Maydell
  1 sibling, 1 reply; 114+ messages in thread
From: Richard Henderson @ 2018-05-22 16:33 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel
  Cc: patches, Paolo Bonzini, Alex Bennée

On 05/21/2018 07:03 AM, Peter Maydell wrote:
> As part of plumbing MemTxAttrs down to the IOMMU translate method,
> add MemTxAttrs as an argument to flatview_access_valid().
> Its callers now all have an attrs value to hand, so we can
> correct our earlier temporary use of MEMTXATTRS_UNSPECIFIED.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

>              /* When our callers all have attrs we'll pass them through here */
> -            if (!memory_region_access_valid(mr, xlat, l, is_write,
> -                                            MEMTXATTRS_UNSPECIFIED)) {
> +            if (!memory_region_access_valid(mr, xlat, l, is_write, attrs)) {

Kill the temporary comment too.


r~

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 10/27] Make flatview_translate() take a MemTxAttrs argument
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 10/27] Make flatview_translate() " Peter Maydell
  2018-05-22 10:58   ` Alex Bennée
@ 2018-05-22 16:33   ` Richard Henderson
  1 sibling, 0 replies; 114+ messages in thread
From: Richard Henderson @ 2018-05-22 16:33 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel
  Cc: patches, Paolo Bonzini, Alex Bennée

On 05/21/2018 07:03 AM, Peter Maydell wrote:
> As part of plumbing MemTxAttrs down to the IOMMU translate method,
> add MemTxAttrs as an argument to flatview_translate(); all its
> callers now have attrs available.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 09/27] Make flatview_access_valid() take a MemTxAttrs argument
  2018-05-22 16:33   ` Richard Henderson
@ 2018-05-22 16:37     ` Peter Maydell
  0 siblings, 0 replies; 114+ messages in thread
From: Peter Maydell @ 2018-05-22 16:37 UTC (permalink / raw)
  To: Richard Henderson
  Cc: qemu-arm, QEMU Developers, patches, Paolo Bonzini, Alex Bennée

On 22 May 2018 at 17:33, Richard Henderson <rth@twiddle.net> wrote:
> On 05/21/2018 07:03 AM, Peter Maydell wrote:
>> As part of plumbing MemTxAttrs down to the IOMMU translate method,
>> add MemTxAttrs as an argument to flatview_access_valid().
>> Its callers now all have an attrs value to hand, so we can
>> correct our earlier temporary use of MEMTXATTRS_UNSPECIFIED.
>>
>> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
>> ---
>
> Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
>
>>              /* When our callers all have attrs we'll pass them through here */
>> -            if (!memory_region_access_valid(mr, xlat, l, is_write,
>> -                                            MEMTXATTRS_UNSPECIFIED)) {
>> +            if (!memory_region_access_valid(mr, xlat, l, is_write, attrs)) {
>
> Kill the temporary comment too.

Oops, yes.

thanks
-- PMM

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 11/27] Make address_space_get_iotlb_entry() take a MemTxAttrs argument
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 11/27] Make address_space_get_iotlb_entry() " Peter Maydell
  2018-05-22 11:00   ` Alex Bennée
@ 2018-05-22 17:29   ` Richard Henderson
  1 sibling, 0 replies; 114+ messages in thread
From: Richard Henderson @ 2018-05-22 17:29 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel
  Cc: patches, Paolo Bonzini, Alex Bennée

On 05/21/2018 07:03 AM, Peter Maydell wrote:
> As part of plumbing MemTxAttrs down to the IOMMU translate method,
> add MemTxAttrs as an argument to address_space_get_iotlb_entry().
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 12/27] Make flatview_do_translate() take a MemTxAttrs argument
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 12/27] Make flatview_do_translate() " Peter Maydell
  2018-05-22 11:00   ` Alex Bennée
@ 2018-05-22 17:29   ` Richard Henderson
  1 sibling, 0 replies; 114+ messages in thread
From: Richard Henderson @ 2018-05-22 17:29 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel
  Cc: patches, Paolo Bonzini, Alex Bennée

On 05/21/2018 07:03 AM, Peter Maydell wrote:
> As part of plumbing MemTxAttrs down to the IOMMU translate method,
> add MemTxAttrs as an argument to flatview_do_translate().
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 13/27] Make address_space_translate_iommu take a MemTxAttrs argument
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 13/27] Make address_space_translate_iommu " Peter Maydell
  2018-05-22 11:00   ` Alex Bennée
@ 2018-05-22 17:30   ` Richard Henderson
  1 sibling, 0 replies; 114+ messages in thread
From: Richard Henderson @ 2018-05-22 17:30 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel
  Cc: patches, Paolo Bonzini, Alex Bennée

On 05/21/2018 07:03 AM, Peter Maydell wrote:
> As part of plumbing MemTxAttrs down to the IOMMU translate method,
> add MemTxAttrs as an argument to address_space_translate_iommu().
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 14/27] iommu: Add IOMMU index concept to IOMMU API
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 14/27] iommu: Add IOMMU index concept to IOMMU API Peter Maydell
  2018-05-22  3:03   ` Peter Xu
  2018-05-22 12:58   ` Auger Eric
@ 2018-05-22 17:42   ` Richard Henderson
  2018-05-22 17:51     ` Peter Maydell
  2 siblings, 1 reply; 114+ messages in thread
From: Richard Henderson @ 2018-05-22 17:42 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel
  Cc: patches, Paolo Bonzini, Alex Bennée

On 05/21/2018 07:03 AM, Peter Maydell wrote:
> +    /* Return the IOMMU index to use for a given set of transaction attributes.
> +     *
> +     * Optional method: if an IOMMU only supports a single IOMMU index then
> +     * the default implementation of memory_region_iommu_attrs_to_index()
> +     * will return 0.
> +     *
> +     * The indexes supported by an IOMMU must be contiguous, starting at 0.
> +     *
> +     * @iommu: the IOMMUMemoryRegion
> +     * @attrs: memory transaction attributes
> +     */
> +    int (*attrs_to_index)(IOMMUMemoryRegion *iommu, MemTxAttrs attrs);
> +
> +    /* Return the number of IOMMU indexes this IOMMU supports.
> +     *
> +     * Optional method: if this method is not provided, then
> +     * memory_region_iommu_num_indexes() will return 1, indicating that
> +     * only a single IOMMU index is supported.
> +     */

The mispatched callback has been discussed, but would it be equally useful to
simply have a variable here instead of a callback?  Perhaps max_index instead
of num_indexes so that zero-initialization of the structure does the right
thing for existing iommu's.


r~

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 15/27] iommu: Add IOMMU index argument to notifier APIs
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 15/27] iommu: Add IOMMU index argument to notifier APIs Peter Maydell
@ 2018-05-22 17:45   ` Richard Henderson
  2018-05-23  9:08   ` Alex Bennée
  2018-05-24 15:29   ` Auger Eric
  2 siblings, 0 replies; 114+ messages in thread
From: Richard Henderson @ 2018-05-22 17:45 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel
  Cc: patches, Paolo Bonzini, Alex Bennée

On 05/21/2018 07:03 AM, Peter Maydell wrote:
> Add support for multiple IOMMU indexes to the IOMMU notifier APIs.
> When initializing a notifier with iommu_notifier_init(), the caller
> must pass the IOMMU index that it is interested in. When a change
> happens, the IOMMU implementation must pass
> memory_region_notify_iommu() the IOMMU index that has changed and
> that notifiers must be called for.
> 
> IOMMUs which support only a single index don't need to change.
> Callers which only really support working with IOMMUs with a single
> index can use the result of passing MEMTXATTRS_UNSPECIFIED to
> memory_region_iommu_attrs_to_index().
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 14/27] iommu: Add IOMMU index concept to IOMMU API
  2018-05-22 17:42   ` Richard Henderson
@ 2018-05-22 17:51     ` Peter Maydell
  2018-05-22 17:52       ` Richard Henderson
  0 siblings, 1 reply; 114+ messages in thread
From: Peter Maydell @ 2018-05-22 17:51 UTC (permalink / raw)
  To: Richard Henderson
  Cc: qemu-arm, QEMU Developers, patches, Paolo Bonzini, Alex Bennée

On 22 May 2018 at 18:42, Richard Henderson <rth@twiddle.net> wrote:
> On 05/21/2018 07:03 AM, Peter Maydell wrote:
>> +    /* Return the IOMMU index to use for a given set of transaction attributes.
>> +     *
>> +     * Optional method: if an IOMMU only supports a single IOMMU index then
>> +     * the default implementation of memory_region_iommu_attrs_to_index()
>> +     * will return 0.
>> +     *
>> +     * The indexes supported by an IOMMU must be contiguous, starting at 0.
>> +     *
>> +     * @iommu: the IOMMUMemoryRegion
>> +     * @attrs: memory transaction attributes
>> +     */
>> +    int (*attrs_to_index)(IOMMUMemoryRegion *iommu, MemTxAttrs attrs);
>> +
>> +    /* Return the number of IOMMU indexes this IOMMU supports.
>> +     *
>> +     * Optional method: if this method is not provided, then
>> +     * memory_region_iommu_num_indexes() will return 1, indicating that
>> +     * only a single IOMMU index is supported.
>> +     */
>
> The mispatched callback has been discussed, but would it be equally useful to
> simply have a variable here instead of a callback?  Perhaps max_index instead
> of num_indexes so that zero-initialization of the structure does the right
> thing for existing iommu's.

That wouldn't allow for multiple instances of the same class where the
answer is different (eg "my_iommu->has_trustzone_support ? 2 : 1" where
the answer depends on how the instance is configured via QOM properties).

thanks
-- PMM

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 14/27] iommu: Add IOMMU index concept to IOMMU API
  2018-05-22 17:51     ` Peter Maydell
@ 2018-05-22 17:52       ` Richard Henderson
  0 siblings, 0 replies; 114+ messages in thread
From: Richard Henderson @ 2018-05-22 17:52 UTC (permalink / raw)
  To: Peter Maydell
  Cc: qemu-arm, QEMU Developers, patches, Paolo Bonzini, Alex Bennée

On 05/22/2018 10:51 AM, Peter Maydell wrote:
> That wouldn't allow for multiple instances of the same class where the
> answer is different (eg "my_iommu->has_trustzone_support ? 2 : 1" where
> the answer depends on how the instance is configured via QOM properties).

Ah.  I had somehow been assuming those would be different classes.
Ok then,

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 16/27] iommu: Add IOMMU index argument to translate method
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 16/27] iommu: Add IOMMU index argument to translate method Peter Maydell
@ 2018-05-22 18:06   ` Richard Henderson
  2018-05-23  9:11   ` Alex Bennée
  1 sibling, 0 replies; 114+ messages in thread
From: Richard Henderson @ 2018-05-22 18:06 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel
  Cc: patches, Paolo Bonzini, Alex Bennée

On 05/21/2018 07:03 AM, Peter Maydell wrote:
> Add an IOMMU index argument to the translate method of
> IOMMUs. Since all of our current IOMMU implementations
> support only a single IOMMU index, this has no effect
> on the behaviour.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 14/27] iommu: Add IOMMU index concept to IOMMU API
  2018-05-22 11:11         ` Peter Maydell
@ 2018-05-23  1:06           ` Peter Xu
  2018-05-23 11:47             ` Peter Maydell
  0 siblings, 1 reply; 114+ messages in thread
From: Peter Xu @ 2018-05-23  1:06 UTC (permalink / raw)
  To: Peter Maydell
  Cc: qemu-arm, QEMU Developers, Paolo Bonzini, Richard Henderson,
	Alex Bennée, patches, David Gibson, Alex Williamson

On Tue, May 22, 2018 at 12:11:38PM +0100, Peter Maydell wrote:
> On 22 May 2018 at 12:02, Peter Xu <peterx@redhat.com> wrote:
> > On Tue, May 22, 2018 at 09:40:44AM +0100, Peter Maydell wrote:
> >> On 22 May 2018 at 04:03, Peter Xu <peterx@redhat.com> wrote:
> >> The reason for not just passing in the transaction attributes to
> >> translate is that
> >> (a) the iommu index abstraction makes the notifier setup simpler:
> >> rather than having to have some indication in the API of which
> >> of the transaction attributes are important and which the notifier
> >> cares about, we can just use indexs
> >
> > Hmm, so here IIUC we'll have a new IOMMU notifier that will only
> > listen to part of the IOMMU notifies, e.g., when attrs.secure=true.
> > Yes I think adding something into IOMMUNotifier might work, but just
> > to mention that in IOMMUTLBEntry we have IOMMUTLBEntry.target_as
> > defined.  Until now it's hardly used at least on x86 platform since
> > all of the translations on x86 are targeted to the system RAM.
> > However it seems to be quite tailored in this case since it seems to
> > me that different attrs.secure value for translations should be based
> > on different address spaces too.  Then in the IOMMU notifiers that
> > would care about MemTxAttrs, could it be possible to identify that by
> > check against the IOMMUTLBEntry.target_as?
> 
> No, because you can have a single address space that receives
> transactions with various attributes. (Again, the MPC is an
> example of this.)
> 
> >> (b) it means that it's harder to write an iommu with the bug that
> >> it looks at parts of the transaction attributes that it didn't
> >> claim were important in the notifier API
> >
> > It is just confusing to me when I looked at current translate()
> > interface (I copied it from some other patch of the series):
> >
> > @@ -252,9 +252,10 @@ typedef struct IOMMUMemoryRegionClass {
> >       * @iommu: the IOMMUMemoryRegion
> >       * @hwaddr: address to be translated within the memory region
> >       * @flag: requested access permissions
> > +     * @iommu_idx: IOMMU index for the translation
> >       */
> >      IOMMUTLBEntry (*translate)(IOMMUMemoryRegion *iommu, hwaddr addr,
> > -                               IOMMUAccessFlags flag);
> > +                               IOMMUAccessFlags flag, int iommu_idx);
> >
> > The "iommu_idx" parameter is really hard to understand here at the
> > first glance.  Now I think I understand that it is somehow related to
> > the MemTxAttrs, but still it will take time to understand.
> 
> The part of the documentation where I try to explain the general
> idea is in this patch, in the comment at the top of the struct:
> 
> + * Conceptually an IOMMU provides a mapping from input address
> + * to an output TLB entry. If the IOMMU is aware of memory transaction
> + * attributes and the output TLB entry depends on the transaction
> + * attributes, we represent this using IOMMU indexes. Each index
> + * selects a particular translation table that the IOMMU has:
> + *   @attrs_to_index returns the IOMMU index for a set of transaction
> attributes
> + *   @translate takes an input address and an IOMMU index
> + * and the mapping returned can only depend on the input address and the
> + * IOMMU index.
> + *
> + * Most IOMMUs don't care about the transaction attributes and support
> + * only a single IOMMU index. A more complex IOMMU might have one index
> + * for secure transactions and one for non-secure transactions.
> 
> Do you have suggestions for how to improve on this?

Not yet.  But I have some other questions below...

> 
> > And if we see current implementation for this (still, I copied code
> > from other patch in the series to here to ease discussion):
> >
> > @@ -498,8 +498,15 @@ static MemoryRegionSection address_space_translate_iommu(IOMMUMemoryRegion *iomm
> >      do {
> >          hwaddr addr = *xlat;
> >          IOMMUMemoryRegionClass *imrc = memory_region_get_iommu_class_nocheck(iommu_mr);
> > -        IOMMUTLBEntry iotlb = imrc->translate(iommu_mr, addr, is_write ?
> > -                                              IOMMU_WO : IOMMU_RO);
> > +        int iommu_idx = 0;
> > +        IOMMUTLBEntry iotlb;
> > +
> > +        if (imrc->attrs_to_index) {
> > +            iommu_idx = imrc->attrs_to_index(iommu_mr, attrs);
> > +        }
> > +
> > +        iotlb = imrc->translate(iommu_mr, addr, is_write ?
> > +                                IOMMU_WO : IOMMU_RO, iommu_idx);
> >
> > Here what if we pass attrs directly into imrc->translate() and just
> > call imrc->attrs_to_index() inside the arch-dependent translate()
> > function?  Will that work too?
> 
> You don't always have the attributes at the point where you want
> to call translate. (For instance, memory_region_notify_iommu()
> doesn't have attributes.)
> 
> I started off with "pass the tx attrs into the translate method",
> which is fine for the code flows which are actually doing
> memory transactions, but breaks down when you try to incorporate
> notifiers.

Could you elaborate a bit more on why IOMMU notifier failed to
corporate when passing in MemTxAttrs?  I am not sure I caught the idea
here, but can we copy the MemTxAttrs into IOMMUTLBEntry when
translating, then in IOMMU notifiers we can know the attrs (if that is
what MPC wants)?

> 
> > I had a quick glance at the series, I have no thorough idea on the
> > whole stuff, but I'd say some of the patches are exactly what I wanted
> > if to support MemTxAttrs in VT-d emulation one day (now DMAR of VT-d
> > is bypassing MemTxAttrs and IMHO that's incorrect).  If we can somehow
> > pass in the MemTxAttrs then that'll be perfect and I can continue to
> > work on that.  If we pass in iommu_idx now instead, it would take some
> > time for me to figure out how to further achieve the same goal for
> > VT-d in the future, e.g., I would still want to pass in MemTxAttrs,
> > but that's obviously duplicated with iommu_idx.
> 
> The idea is that you should never need to pass in the MemTxAttrs,
> because everything that the IOMMU might care about in the tx attrs
> must be encoded into the iommu index. (The point where the IOMMU
> gets to do that encoding is in its attrs_to_index() method.)

For the DMAR issue I would care about MemTxAttrs.requester_id.  Just
to confirm - do you mean I encode the 16bits field into iommu_idx too,
or is there any smarter way to do so?  Asked since otherwise iommu_idx
will gradually grow into another MemTxAttrs to me.

Thanks,

-- 
Peter Xu

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 15/27] iommu: Add IOMMU index argument to notifier APIs
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 15/27] iommu: Add IOMMU index argument to notifier APIs Peter Maydell
  2018-05-22 17:45   ` Richard Henderson
@ 2018-05-23  9:08   ` Alex Bennée
  2018-06-04 13:03     ` Peter Maydell
  2018-05-24 15:29   ` Auger Eric
  2 siblings, 1 reply; 114+ messages in thread
From: Alex Bennée @ 2018-05-23  9:08 UTC (permalink / raw)
  To: Peter Maydell
  Cc: qemu-arm, qemu-devel, patches, Paolo Bonzini, Richard Henderson


Peter Maydell <peter.maydell@linaro.org> writes:

> Add support for multiple IOMMU indexes to the IOMMU notifier APIs.
> When initializing a notifier with iommu_notifier_init(), the caller
> must pass the IOMMU index that it is interested in. When a change
> happens, the IOMMU implementation must pass
> memory_region_notify_iommu() the IOMMU index that has changed and
> that notifiers must be called for.
>
> IOMMUs which support only a single index don't need to change.
> Callers which only really support working with IOMMUs with a single
> index can use the result of passing MEMTXATTRS_UNSPECIFIED to
> memory_region_iommu_attrs_to_index().
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  include/exec/memory.h    | 11 ++++++++++-
>  hw/i386/intel_iommu.c    |  4 ++--
>  hw/ppc/spapr_iommu.c     |  2 +-
>  hw/s390x/s390-pci-inst.c |  4 ++--
>  hw/vfio/common.c         |  6 +++++-
>  hw/virtio/vhost.c        |  7 ++++++-
>  memory.c                 |  8 +++++++-
>  7 files changed, 33 insertions(+), 9 deletions(-)
>
> diff --git a/include/exec/memory.h b/include/exec/memory.h
> index f6226fb263..4e6b125add 100644
> --- a/include/exec/memory.h
> +++ b/include/exec/memory.h
> @@ -71,6 +71,7 @@ struct IOMMUTLBEntry {
>      hwaddr           iova;
>      hwaddr           translated_addr;
>      hwaddr           addr_mask;  /* 0xfff = 4k translation */
> +    int              iommu_idx;
>      IOMMUAccessFlags perm;
>  };
>
> @@ -98,18 +99,21 @@ struct IOMMUNotifier {
>      /* Notify for address space range start <= addr <= end */
>      hwaddr start;
>      hwaddr end;
> +    int iommu_idx;

Its a minor thing but are we ever expecting iommu_idx to ever be
negative?

> --- a/memory.c
> +++ b/memory.c
> @@ -1802,6 +1802,9 @@ void memory_region_register_iommu_notifier(MemoryRegion *mr,
>      iommu_mr = IOMMU_MEMORY_REGION(mr);
>      assert(n->notifier_flags != IOMMU_NOTIFIER_NONE);
>      assert(n->start <= n->end);
> +    assert(n->iommu_idx >= 0 &&
> +           n->iommu_idx < memory_region_iommu_num_indexes(iommu_mr));
> +

And then this would only have to assert we haven't exceeded the upper bound.

--
Alex Bennée

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 16/27] iommu: Add IOMMU index argument to translate method
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 16/27] iommu: Add IOMMU index argument to translate method Peter Maydell
  2018-05-22 18:06   ` Richard Henderson
@ 2018-05-23  9:11   ` Alex Bennée
  1 sibling, 0 replies; 114+ messages in thread
From: Alex Bennée @ 2018-05-23  9:11 UTC (permalink / raw)
  To: Peter Maydell
  Cc: qemu-arm, qemu-devel, patches, Paolo Bonzini, Richard Henderson


Peter Maydell <peter.maydell@linaro.org> writes:

> Add an IOMMU index argument to the translate method of
> IOMMUs. Since all of our current IOMMU implementations
> support only a single IOMMU index, this has no effect
> on the behaviour.
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Modulo comment about signed indexes in previous commit:

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

> ---
>  include/exec/memory.h    |  3 ++-
>  exec.c                   | 11 +++++++++--
>  hw/alpha/typhoon.c       |  3 ++-
>  hw/arm/smmuv3.c          |  2 +-
>  hw/dma/rc4030.c          |  2 +-
>  hw/i386/amd_iommu.c      |  2 +-
>  hw/i386/intel_iommu.c    |  2 +-
>  hw/ppc/spapr_iommu.c     |  3 ++-
>  hw/s390x/s390-pci-bus.c  |  2 +-
>  hw/sparc/sun4m_iommu.c   |  3 ++-
>  hw/sparc64/sun4u_iommu.c |  2 +-
>  memory.c                 |  2 +-
>  12 files changed, 24 insertions(+), 13 deletions(-)
>
> diff --git a/include/exec/memory.h b/include/exec/memory.h
> index 4e6b125add..b25cf527bb 100644
> --- a/include/exec/memory.h
> +++ b/include/exec/memory.h
> @@ -252,9 +252,10 @@ typedef struct IOMMUMemoryRegionClass {
>       * @iommu: the IOMMUMemoryRegion
>       * @hwaddr: address to be translated within the memory region
>       * @flag: requested access permissions
> +     * @iommu_idx: IOMMU index for the translation
>       */
>      IOMMUTLBEntry (*translate)(IOMMUMemoryRegion *iommu, hwaddr addr,
> -                               IOMMUAccessFlags flag);
> +                               IOMMUAccessFlags flag, int iommu_idx);
>      /* Returns minimum supported page size in bytes.
>       * If this method is not provided then the minimum is assumed to
>       * be TARGET_PAGE_SIZE.
> diff --git a/exec.c b/exec.c
> index c3baadc349..c9285c9c39 100644
> --- a/exec.c
> +++ b/exec.c
> @@ -498,8 +498,15 @@ static MemoryRegionSection address_space_translate_iommu(IOMMUMemoryRegion *iomm
>      do {
>          hwaddr addr = *xlat;
>          IOMMUMemoryRegionClass *imrc = memory_region_get_iommu_class_nocheck(iommu_mr);
> -        IOMMUTLBEntry iotlb = imrc->translate(iommu_mr, addr, is_write ?
> -                                              IOMMU_WO : IOMMU_RO);
> +        int iommu_idx = 0;
> +        IOMMUTLBEntry iotlb;
> +
> +        if (imrc->attrs_to_index) {
> +            iommu_idx = imrc->attrs_to_index(iommu_mr, attrs);
> +        }
> +
> +        iotlb = imrc->translate(iommu_mr, addr, is_write ?
> +                                IOMMU_WO : IOMMU_RO, iommu_idx);
>
>          if (!(iotlb.perm & (1 << is_write))) {
>              goto unassigned;
> diff --git a/hw/alpha/typhoon.c b/hw/alpha/typhoon.c
> index 6a40869488..d3ed7cdbe8 100644
> --- a/hw/alpha/typhoon.c
> +++ b/hw/alpha/typhoon.c
> @@ -666,7 +666,8 @@ static bool window_translate(TyphoonWindow *win, hwaddr addr,
>     Pchip and generate a machine check interrupt.  */
>  static IOMMUTLBEntry typhoon_translate_iommu(IOMMUMemoryRegion *iommu,
>                                               hwaddr addr,
> -                                             IOMMUAccessFlags flag)
> +                                             IOMMUAccessFlags flag,
> +                                             int iommu_idx)
>  {
>      TyphoonPchip *pchip = container_of(iommu, TyphoonPchip, iommu);
>      IOMMUTLBEntry ret;
> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
> index 42dc521c13..978330900d 100644
> --- a/hw/arm/smmuv3.c
> +++ b/hw/arm/smmuv3.c
> @@ -538,7 +538,7 @@ static int smmuv3_decode_config(IOMMUMemoryRegion *mr, SMMUTransCfg *cfg,
>  }
>
>  static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
> -                                      IOMMUAccessFlags flag)
> +                                      IOMMUAccessFlags flag, int iommu_idx)
>  {
>      SMMUDevice *sdev = container_of(mr, SMMUDevice, iommu);
>      SMMUv3State *s = sdev->smmu;
> diff --git a/hw/dma/rc4030.c b/hw/dma/rc4030.c
> index 5d4833eeca..ccd8612888 100644
> --- a/hw/dma/rc4030.c
> +++ b/hw/dma/rc4030.c
> @@ -491,7 +491,7 @@ static const MemoryRegionOps jazzio_ops = {
>  };
>
>  static IOMMUTLBEntry rc4030_dma_translate(IOMMUMemoryRegion *iommu, hwaddr addr,
> -                                          IOMMUAccessFlags flag)
> +                                          IOMMUAccessFlags flag, int iommu_idx)
>  {
>      rc4030State *s = container_of(iommu, rc4030State, dma_mr);
>      IOMMUTLBEntry ret = {
> diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c
> index 63d46ff6ee..1fd669fef8 100644
> --- a/hw/i386/amd_iommu.c
> +++ b/hw/i386/amd_iommu.c
> @@ -991,7 +991,7 @@ static inline bool amdvi_is_interrupt_addr(hwaddr addr)
>  }
>
>  static IOMMUTLBEntry amdvi_translate(IOMMUMemoryRegion *iommu, hwaddr addr,
> -                                     IOMMUAccessFlags flag)
> +                                     IOMMUAccessFlags flag, int iommu_idx)
>  {
>      AMDVIAddressSpace *as = container_of(iommu, AMDVIAddressSpace, iommu);
>      AMDVIState *s = as->iommu_state;
> diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c
> index b8c9354b0b..a4b9a254bd 100644
> --- a/hw/i386/intel_iommu.c
> +++ b/hw/i386/intel_iommu.c
> @@ -2282,7 +2282,7 @@ static void vtd_mem_write(void *opaque, hwaddr addr,
>  }
>
>  static IOMMUTLBEntry vtd_iommu_translate(IOMMUMemoryRegion *iommu, hwaddr addr,
> -                                         IOMMUAccessFlags flag)
> +                                         IOMMUAccessFlags flag, int iommu_idx)
>  {
>      VTDAddressSpace *vtd_as = container_of(iommu, VTDAddressSpace, iommu);
>      IntelIOMMUState *s = vtd_as->iommu_state;
> diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c
> index 301708e45e..1b0880ac9e 100644
> --- a/hw/ppc/spapr_iommu.c
> +++ b/hw/ppc/spapr_iommu.c
> @@ -112,7 +112,8 @@ static void spapr_tce_free_table(uint64_t *table, int fd, uint32_t nb_table)
>  /* Called from RCU critical section */
>  static IOMMUTLBEntry spapr_tce_translate_iommu(IOMMUMemoryRegion *iommu,
>                                                 hwaddr addr,
> -                                               IOMMUAccessFlags flag)
> +                                               IOMMUAccessFlags flag,
> +                                               int iommu_idx)
>  {
>      sPAPRTCETable *tcet = container_of(iommu, sPAPRTCETable, iommu);
>      uint64_t tce;
> diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c
> index 10da87458e..e3e0ebb7f6 100644
> --- a/hw/s390x/s390-pci-bus.c
> +++ b/hw/s390x/s390-pci-bus.c
> @@ -484,7 +484,7 @@ uint16_t s390_guest_io_table_walk(uint64_t g_iota, hwaddr addr,
>  }
>
>  static IOMMUTLBEntry s390_translate_iommu(IOMMUMemoryRegion *mr, hwaddr addr,
> -                                          IOMMUAccessFlags flag)
> +                                          IOMMUAccessFlags flag, int iommu_idx)
>  {
>      S390PCIIOMMU *iommu = container_of(mr, S390PCIIOMMU, iommu_mr);
>      S390IOTLBEntry *entry;
> diff --git a/hw/sparc/sun4m_iommu.c b/hw/sparc/sun4m_iommu.c
> index b677601fc6..7ca1e3fce4 100644
> --- a/hw/sparc/sun4m_iommu.c
> +++ b/hw/sparc/sun4m_iommu.c
> @@ -282,7 +282,8 @@ static void iommu_bad_addr(IOMMUState *s, hwaddr addr,
>  /* Called from RCU critical section */
>  static IOMMUTLBEntry sun4m_translate_iommu(IOMMUMemoryRegion *iommu,
>                                             hwaddr addr,
> -                                           IOMMUAccessFlags flags)
> +                                           IOMMUAccessFlags flags,
> +                                           int iommu_idx)
>  {
>      IOMMUState *is = container_of(iommu, IOMMUState, iommu);
>      hwaddr page, pa;
> diff --git a/hw/sparc64/sun4u_iommu.c b/hw/sparc64/sun4u_iommu.c
> index eb3aaa87e6..1ef7645ba5 100644
> --- a/hw/sparc64/sun4u_iommu.c
> +++ b/hw/sparc64/sun4u_iommu.c
> @@ -73,7 +73,7 @@
>  /* Called from RCU critical section */
>  static IOMMUTLBEntry sun4u_translate_iommu(IOMMUMemoryRegion *iommu,
>                                             hwaddr addr,
> -                                           IOMMUAccessFlags flag)
> +                                           IOMMUAccessFlags flag, int iommu_idx)
>  {
>      IOMMUState *is = container_of(iommu, IOMMUState, iommu);
>      hwaddr baseaddr, offset;
> diff --git a/memory.c b/memory.c
> index accb28d694..ff6cbf5831 100644
> --- a/memory.c
> +++ b/memory.c
> @@ -1835,7 +1835,7 @@ void memory_region_iommu_replay(IOMMUMemoryRegion *iommu_mr, IOMMUNotifier *n)
>      granularity = memory_region_iommu_get_min_page_size(iommu_mr);
>
>      for (addr = 0; addr < memory_region_size(mr); addr += granularity) {
> -        iotlb = imrc->translate(iommu_mr, addr, IOMMU_NONE);
> +        iotlb = imrc->translate(iommu_mr, addr, IOMMU_NONE, n->iommu_idx);
>          if (iotlb.perm != IOMMU_NONE) {
>              n->notify(n, &iotlb);
>          }


--
Alex Bennée

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 17/27] exec.c: Handle IOMMUs in address_space_translate_for_iotlb()
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 17/27] exec.c: Handle IOMMUs in address_space_translate_for_iotlb() Peter Maydell
@ 2018-05-23  9:51   ` Alex Bennée
  2018-05-23 11:52     ` Peter Maydell
  2018-05-24 19:54     ` Auger Eric
  0 siblings, 2 replies; 114+ messages in thread
From: Alex Bennée @ 2018-05-23  9:51 UTC (permalink / raw)
  To: Peter Maydell
  Cc: qemu-arm, qemu-devel, patches, Paolo Bonzini, Richard Henderson


Peter Maydell <peter.maydell@linaro.org> writes:

> Currently we don't support board configurations that put an IOMMU
> in the path of the CPU's memory transactions, and instead just
> assert() if the memory region fonud in address_space_translate_for_iotlb()
> is an IOMMUMemoryRegion.
>
> Remove this limitation by having the function handle IOMMUs.
> This is mostly straightforward, but we must make sure we have
> a notifier registered for every IOMMU that a transaction has
> passed through, so that we can flush the TLB appropriately
> when any of the IOMMUs change their mappings.
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  include/exec/exec-all.h |   3 +-
>  include/qom/cpu.h       |   3 +
>  accel/tcg/cputlb.c      |   3 +-
>  exec.c                  | 147 +++++++++++++++++++++++++++++++++++++++-
>  4 files changed, 152 insertions(+), 4 deletions(-)
>
> diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
> index 4d09eaba72..e0ff19b711 100644
> --- a/include/exec/exec-all.h
> +++ b/include/exec/exec-all.h
> @@ -469,7 +469,8 @@ void tb_flush_jmp_cache(CPUState *cpu, target_ulong addr);
>
>  MemoryRegionSection *
>  address_space_translate_for_iotlb(CPUState *cpu, int asidx, hwaddr addr,
> -                                  hwaddr *xlat, hwaddr *plen);
> +                                  hwaddr *xlat, hwaddr *plen,
> +                                  MemTxAttrs attrs, int *prot);
>  hwaddr memory_region_section_get_iotlb(CPUState *cpu,
>                                         MemoryRegionSection *section,
>                                         target_ulong vaddr,
> diff --git a/include/qom/cpu.h b/include/qom/cpu.h
> index 9d3afc6c75..d4a30149dd 100644
> --- a/include/qom/cpu.h
> +++ b/include/qom/cpu.h
> @@ -429,6 +429,9 @@ struct CPUState {
>      uint16_t pending_tlb_flush;
>
>      int hvf_fd;
> +
> +    /* track IOMMUs whose translations we've cached in the TCG TLB */
> +    GSList *iommu_notifiers;

So we are only concerned about TCG IOMMU notifiers here, specifically
TCGIOMMUNotifier structures. Why not just use a GArray and save
ourselves chasing pointers?

>  };
>
>  QTAILQ_HEAD(CPUTailQ, CPUState);
> diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c
> index 05439039e9..c8acaf21e9 100644
> --- a/accel/tcg/cputlb.c
> +++ b/accel/tcg/cputlb.c
> @@ -632,7 +632,8 @@ void tlb_set_page_with_attrs(CPUState *cpu, target_ulong vaddr,
>      }
>
>      sz = size;
> -    section = address_space_translate_for_iotlb(cpu, asidx, paddr, &xlat, &sz);
> +    section = address_space_translate_for_iotlb(cpu, asidx, paddr, &xlat, &sz,
> +                                                attrs, &prot);
>      assert(sz >= TARGET_PAGE_SIZE);
>
>      tlb_debug("vaddr=" TARGET_FMT_lx " paddr=0x" TARGET_FMT_plx
> diff --git a/exec.c b/exec.c
> index c9285c9c39..6c8f2dcc3f 100644
> --- a/exec.c
> +++ b/exec.c
> @@ -650,18 +650,158 @@ MemoryRegion *flatview_translate(FlatView *fv, hwaddr addr, hwaddr *xlat,
>      return mr;
>  }
>
> +typedef struct TCGIOMMUNotifier {
> +    IOMMUNotifier n;
> +    MemoryRegion *mr;
> +    CPUState *cpu;

This seems superfluous if we are storing the list of notifiers in the CPUState

> +    int iommu_idx;
> +    bool active;
> +} TCGIOMMUNotifier;
> +
> +static void tcg_iommu_unmap_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb)
> +{
> +    TCGIOMMUNotifier *notifier = container_of(n, TCGIOMMUNotifier, n);
> +
> +    if (!notifier->active) {
> +        return;
> +    }
> +    tlb_flush(notifier->cpu);
> +    notifier->active = false;
> +    /* We leave the notifier struct on the list to avoid reallocating it later.
> +     * Generally the number of IOMMUs a CPU deals with will be small.
> +     * In any case we can't unregister the iommu notifier from a notify
> +     * callback.
> +     */
> +}
> +
> +static gint tcg_iommu_find_notifier(gconstpointer a, gconstpointer b)
> +{
> +    TCGIOMMUNotifier *notifier = (TCGIOMMUNotifier *)a;
> +    TCGIOMMUNotifier *seeking = (TCGIOMMUNotifier *)b;
> +
> +    if (notifier->mr == seeking->mr &&
> +        notifier->iommu_idx == seeking->iommu_idx) {
> +        return 0;
> +    }
> +    return 1;
> +}
> +
> +static void tcg_register_iommu_notifier(CPUState *cpu,
> +                                        IOMMUMemoryRegion *iommu_mr,
> +                                        int iommu_idx)
> +{
> +    /* Make sure this CPU has an IOMMU notifier registered for this
> +     * IOMMU/IOMMU index combination, so that we can flush its TLB
> +     * when the IOMMU tells us the mappings we've cached have changed.
> +     */
> +    TCGIOMMUNotifier seeking = {
> +        .mr = MEMORY_REGION(iommu_mr),
> +        .iommu_idx = iommu_idx,
> +    };
> +    TCGIOMMUNotifier *notifier;
> +    GSList *found = g_slist_find_custom(cpu->iommu_notifiers,
> +                                        &seeking,
> +                                        tcg_iommu_find_notifier);
> +    if (found) {
> +        notifier = found->data;
> +    } else {
> +        notifier = g_new0(TCGIOMMUNotifier, 1);
> +        notifier->mr = seeking.mr;
> +        notifier->iommu_idx = iommu_idx;
> +        notifier->cpu = cpu;
> +        /* Rather than trying to register interest in the specific part
> +         * of the iommu's address space that we've accessed and then
> +         * expand it later as subsequent accesses touch more of it, we
> +         * just register interest in the whole thing, on the assumption
> +         * that iommu reconfiguration will be rare.
> +         */
> +        iommu_notifier_init(&notifier->n,
> +                            tcg_iommu_unmap_notify,
> +                            IOMMU_NOTIFIER_UNMAP,
> +                            0,
> +                            HWADDR_MAX,
> +                            iommu_idx);
> +        memory_region_register_iommu_notifier(notifier->mr, &notifier->n);
> +        cpu->iommu_notifiers = g_slist_prepend(cpu->iommu_notifiers,
> +                                               notifier);
> +    }
> +    if (!notifier->active) {
> +        notifier->active = true;
> +    }
> +}
> +
> +static void tcg_iommu_notifier_destroy(gpointer data)
> +{
> +    TCGIOMMUNotifier *notifier = data;
> +
> +    if (notifier->active) {
> +        memory_region_unregister_iommu_notifier(notifier->mr, &notifier->n);
> +    }
> +    g_free(notifier);
> +}
> +
> +static void tcg_iommu_free_notifier_list(CPUState *cpu)
> +{
> +    /* Destroy the CPU's notifier list */
> +    g_slist_free_full(cpu->iommu_notifiers, tcg_iommu_notifier_destroy);
> +    cpu->iommu_notifiers = NULL;
> +}
> +
>  /* Called from RCU critical section */
>  MemoryRegionSection *
>  address_space_translate_for_iotlb(CPUState *cpu, int asidx, hwaddr addr,
> -                                  hwaddr *xlat, hwaddr *plen)
> +                                  hwaddr *xlat, hwaddr *plen,
> +                                  MemTxAttrs attrs, int *prot)
>  {
>      MemoryRegionSection *section;
> +    IOMMUMemoryRegion *iommu_mr;
> +    IOMMUMemoryRegionClass *imrc;
> +    IOMMUTLBEntry iotlb;
> +    int iommu_idx;
>      AddressSpaceDispatch *d = atomic_rcu_read(&cpu->cpu_ases[asidx].memory_dispatch);
>
> -    section = address_space_translate_internal(d, addr, xlat, plen, false);
> +    for (;;) {
> +        section = address_space_translate_internal(d, addr, &addr, plen, false);
> +
> +        iommu_mr = memory_region_get_iommu(section->mr);
> +        if (!iommu_mr) {
> +            break;
> +        }
> +
> +        imrc = memory_region_get_iommu_class_nocheck(iommu_mr);
> +
> +        iommu_idx = imrc->attrs_to_index(iommu_mr, attrs);
> +        tcg_register_iommu_notifier(cpu, iommu_mr, iommu_idx);
> +        /* We need all the permissions, so pass IOMMU_NONE so the IOMMU
> +         * doesn't short-cut its translation table walk.
> +         */
> +        iotlb = imrc->translate(iommu_mr, addr, IOMMU_NONE, iommu_idx);
> +        addr = ((iotlb.translated_addr & ~iotlb.addr_mask)
> +                | (addr & iotlb.addr_mask));
> +        /* Update the caller's prot bits to remove permissions the IOMMU
> +         * is giving us a failure response for. If we get down to no
> +         * permissions left at all we can give up now.
> +         */
> +        if (!(iotlb.perm & IOMMU_RO)) {
> +            *prot &= ~(PAGE_READ | PAGE_EXEC);
> +        }
> +        if (!(iotlb.perm & IOMMU_WO)) {
> +            *prot &= ~PAGE_WRITE;
> +        }
> +
> +        if (!*prot) {
> +            goto translate_fail;
> +        }
> +
> +        d = flatview_to_dispatch(address_space_to_flatview(iotlb.target_as));
> +    }
>
>      assert(!memory_region_is_iommu(section->mr));
> +    *xlat = addr;
>      return section;
> +
> +translate_fail:
> +    return &d->map.sections[PHYS_SECTION_UNASSIGNED];
>  }
>  #endif
>
> @@ -820,6 +960,9 @@ void cpu_exec_unrealizefn(CPUState *cpu)
>      if (qdev_get_vmsd(DEVICE(cpu)) == NULL) {
>          vmstate_unregister(NULL, &vmstate_cpu_common, cpu);
>      }
> +#ifndef CONFIG_USER_ONLY
> +    tcg_iommu_free_notifier_list(cpu);
> +#endif
>  }
>
>  Property cpu_common_props[] = {


--
Alex Bennée

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 18/27] hw/misc/tz-mpc.c: Implement the Arm TrustZone Memory Protection Controller
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 18/27] hw/misc/tz-mpc.c: Implement the Arm TrustZone Memory Protection Controller Peter Maydell
  2018-05-22 11:30   ` Auger Eric
@ 2018-05-23 10:41   ` Alex Bennée
  1 sibling, 0 replies; 114+ messages in thread
From: Alex Bennée @ 2018-05-23 10:41 UTC (permalink / raw)
  To: Peter Maydell
  Cc: qemu-arm, qemu-devel, patches, Paolo Bonzini, Richard Henderson


Peter Maydell <peter.maydell@linaro.org> writes:

> Implement the Arm TrustZone Memory Protection Controller, which sits
> in front of RAM and allows secure software to configure it to either
> pass through or reject transactions.
>
> We implement the MPC as a QEMU IOMMU, which will direct transactions
> either through to the devices and memory behind it or to a special
> "never works" AddressSpace if they are blocked.
>
> This initial commit implements the skeleton of the device:
>  * it always permits accesses
>  * it doesn't implement most of the registers
>  * it doesn't implement the interrupt or other behaviour
>    for blocked transactions
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

With the caveat I haven't dived into the detail of the MPC but the
skeleton looks good to me:

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>


> ---
>  hw/misc/Makefile.objs           |   1 +
>  include/hw/misc/tz-mpc.h        |  70 ++++++
>  hw/misc/tz-mpc.c                | 381 ++++++++++++++++++++++++++++++++
>  MAINTAINERS                     |   2 +
>  default-configs/arm-softmmu.mak |   1 +
>  hw/misc/trace-events            |   7 +
>  6 files changed, 462 insertions(+)
>  create mode 100644 include/hw/misc/tz-mpc.h
>  create mode 100644 hw/misc/tz-mpc.c
>
> diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
> index 00e834d0f0..7295e676a6 100644
> --- a/hw/misc/Makefile.objs
> +++ b/hw/misc/Makefile.objs
> @@ -61,6 +61,7 @@ obj-$(CONFIG_MIPS_ITU) += mips_itu.o
>  obj-$(CONFIG_MPS2_FPGAIO) += mps2-fpgaio.o
>  obj-$(CONFIG_MPS2_SCC) += mps2-scc.o
>
> +obj-$(CONFIG_TZ_MPC) += tz-mpc.o
>  obj-$(CONFIG_TZ_PPC) += tz-ppc.o
>  obj-$(CONFIG_IOTKIT_SECCTL) += iotkit-secctl.o
>
> diff --git a/include/hw/misc/tz-mpc.h b/include/hw/misc/tz-mpc.h
> new file mode 100644
> index 0000000000..b5eaf1699e
> --- /dev/null
> +++ b/include/hw/misc/tz-mpc.h
> @@ -0,0 +1,70 @@
> +/*
> + * ARM TrustZone memory protection controller emulation
> + *
> + * Copyright (c) 2018 Linaro Limited
> + * Written by Peter Maydell
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 or
> + * (at your option) any later version.
> + */
> +
> +/* This is a model of the TrustZone memory protection controller (MPC).
> + * It is documented in the ARM CoreLink SIE-200 System IP for Embedded TRM
> + * (DDI 0571G):
> + * https://developer.arm.com/products/architecture/m-profile/docs/ddi0571/g
> + *
> + * The MPC sits in front of memory and allows secure software to
> + * configure it to either pass through or reject transactions.
> + * Rejected transactions may be configured to either be aborted, or to
> + * behave as RAZ/WI. An interrupt can be signalled for a rejected transaction.
> + *
> + * The MPC has a register interface which the guest uses to configure it.
> + *
> + * QEMU interface:
> + * + sysbus MMIO region 0: MemoryRegion for the MPC's config registers
> + * + sysbus MMIO region 1: MemoryRegion for the upstream end of the MPC
> + * + Property "downstream": MemoryRegion defining the downstream memory
> + * + Named GPIO output "irq": set for a transaction-failed interrupt
> + */
> +
> +#ifndef TZ_MPC_H
> +#define TZ_MPC_H
> +
> +#include "hw/sysbus.h"
> +
> +#define TYPE_TZ_MPC "tz-mpc"
> +#define TZ_MPC(obj) OBJECT_CHECK(TZMPC, (obj), TYPE_TZ_MPC)
> +
> +#define TZ_NUM_PORTS 16
> +
> +#define TYPE_TZ_MPC_IOMMU_MEMORY_REGION "tz-mpc-iommu-memory-region"
> +
> +typedef struct TZMPC TZMPC;
> +
> +struct TZMPC {
> +    /*< private >*/
> +    SysBusDevice parent_obj;
> +
> +    /*< public >*/
> +
> +    qemu_irq irq;
> +
> +    /* Properties */
> +    MemoryRegion *downstream;
> +
> +    hwaddr blocksize;
> +    uint32_t blk_max;
> +
> +    /* MemoryRegions exposed to user */
> +    MemoryRegion regmr;
> +    IOMMUMemoryRegion upstream;
> +
> +    /* MemoryRegion used internally */
> +    MemoryRegion blocked_io;
> +
> +    AddressSpace downstream_as;
> +    AddressSpace blocked_io_as;
> +};
> +
> +#endif
> diff --git a/hw/misc/tz-mpc.c b/hw/misc/tz-mpc.c
> new file mode 100644
> index 0000000000..d4467ccc3b
> --- /dev/null
> +++ b/hw/misc/tz-mpc.c
> @@ -0,0 +1,381 @@
> +/*
> + * ARM TrustZone memory protection controller emulation
> + *
> + * Copyright (c) 2018 Linaro Limited
> + * Written by Peter Maydell
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 or
> + * (at your option) any later version.
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qemu/log.h"
> +#include "qapi/error.h"
> +#include "trace.h"
> +#include "hw/sysbus.h"
> +#include "hw/registerfields.h"
> +#include "hw/misc/tz-mpc.h"
> +
> +/* Our IOMMU has two IOMMU indexes, one for secure transactions and one for
> + * non-secure transactions.
> + */
> +enum {
> +    IOMMU_IDX_S,
> +    IOMMU_IDX_NS,
> +    IOMMU_NUM_INDEXES,
> +};
> +
> +/* Config registers */
> +REG32(CTRL, 0x00)
> +REG32(BLK_MAX, 0x10)
> +REG32(BLK_CFG, 0x14)
> +REG32(BLK_IDX, 0x18)
> +REG32(BLK_LUT, 0x1c)
> +REG32(INT_STAT, 0x20)
> +REG32(INT_CLEAR, 0x24)
> +REG32(INT_EN, 0x28)
> +REG32(INT_INFO1, 0x2c)
> +REG32(INT_INFO2, 0x30)
> +REG32(INT_SET, 0x34)
> +REG32(PIDR4, 0xfd0)
> +REG32(PIDR5, 0xfd4)
> +REG32(PIDR6, 0xfd8)
> +REG32(PIDR7, 0xfdc)
> +REG32(PIDR0, 0xfe0)
> +REG32(PIDR1, 0xfe4)
> +REG32(PIDR2, 0xfe8)
> +REG32(PIDR3, 0xfec)
> +REG32(CIDR0, 0xff0)
> +REG32(CIDR1, 0xff4)
> +REG32(CIDR2, 0xff8)
> +REG32(CIDR3, 0xffc)
> +
> +static const uint8_t tz_mpc_idregs[] = {
> +    0x04, 0x00, 0x00, 0x00,
> +    0x60, 0xb8, 0x1b, 0x00,
> +    0x0d, 0xf0, 0x05, 0xb1,
> +};
> +
> +static MemTxResult tz_mpc_reg_read(void *opaque, hwaddr addr,
> +                                   uint64_t *pdata,
> +                                   unsigned size, MemTxAttrs attrs)
> +{
> +    uint64_t r;
> +    uint32_t offset = addr & ~0x3;
> +
> +    switch (offset) {
> +    case A_PIDR4:
> +    case A_PIDR5:
> +    case A_PIDR6:
> +    case A_PIDR7:
> +    case A_PIDR0:
> +    case A_PIDR1:
> +    case A_PIDR2:
> +    case A_PIDR3:
> +    case A_CIDR0:
> +    case A_CIDR1:
> +    case A_CIDR2:
> +    case A_CIDR3:
> +        r = tz_mpc_idregs[(offset - A_PIDR4) / 4];
> +        break;
> +    case A_INT_CLEAR:
> +    case A_INT_SET:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "TZ MPC register read: write-only offset 0x%x\n",
> +                      offset);
> +        r = 0;
> +        break;
> +    default:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "TZ MPC register read: bad offset 0x%x\n", offset);
> +        r = 0;
> +        break;
> +    }
> +
> +    if (size != 4) {
> +        /* None of our registers are read-sensitive (except BLK_LUT,
> +         * which can special case the "size not 4" case), so just
> +         * pull the right bytes out of the word read result.
> +         */
> +        r = extract32(r, (addr & 3) * 8, size * 8);
> +    }
> +
> +    trace_tz_mpc_reg_read(addr, r, size);
> +    *pdata = r;
> +    return MEMTX_OK;
> +}
> +
> +static MemTxResult tz_mpc_reg_write(void *opaque, hwaddr addr,
> +                                    uint64_t value,
> +                                    unsigned size, MemTxAttrs attrs)
> +{
> +    uint32_t offset = addr & ~0x3;
> +
> +    trace_tz_mpc_reg_write(addr, value, size);
> +
> +    if (size != 4) {
> +        /* Expand the byte or halfword write to a full word size.
> +         * In most cases we can do this with zeroes; the exceptions
> +         * are CTRL, BLK_IDX and BLK_LUT.
> +         */
> +        uint32_t oldval;
> +
> +        switch (offset) {
> +            /* As we add support for registers which need expansions
> +             * other than zeroes we'll fill in cases here.
> +             */
> +        default:
> +            oldval = 0;
> +            break;
> +        }
> +        value = deposit32(oldval, (addr & 3) * 8, size * 8, value);
> +    }
> +
> +    switch (offset) {
> +    case A_PIDR4:
> +    case A_PIDR5:
> +    case A_PIDR6:
> +    case A_PIDR7:
> +    case A_PIDR0:
> +    case A_PIDR1:
> +    case A_PIDR2:
> +    case A_PIDR3:
> +    case A_CIDR0:
> +    case A_CIDR1:
> +    case A_CIDR2:
> +    case A_CIDR3:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "TZ MPC register write: read-only offset 0x%x\n", offset);
> +        break;
> +    default:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "TZ MPC register write: bad offset 0x%x\n", offset);
> +        break;
> +    }
> +
> +    return MEMTX_OK;
> +}
> +
> +static const MemoryRegionOps tz_mpc_reg_ops = {
> +    .read_with_attrs = tz_mpc_reg_read,
> +    .write_with_attrs = tz_mpc_reg_write,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +    .valid.min_access_size = 1,
> +    .valid.max_access_size = 4,
> +    .impl.min_access_size = 1,
> +    .impl.max_access_size = 4,
> +};
> +
> +/* Accesses only reach these read and write functions if the MPC is
> + * blocking them; non-blocked accesses go directly to the downstream
> + * memory region without passing through this code.
> + */
> +static MemTxResult tz_mpc_mem_blocked_read(void *opaque, hwaddr addr,
> +                                           uint64_t *pdata,
> +                                           unsigned size, MemTxAttrs attrs)
> +{
> +    trace_tz_mpc_mem_blocked_read(addr, size, attrs.secure);
> +
> +    *pdata = 0;
> +    return MEMTX_OK;
> +}
> +
> +static MemTxResult tz_mpc_mem_blocked_write(void *opaque, hwaddr addr,
> +                                            uint64_t value,
> +                                            unsigned size, MemTxAttrs attrs)
> +{
> +    trace_tz_mpc_mem_blocked_write(addr, value, size, attrs.secure);
> +
> +    return MEMTX_OK;
> +}
> +
> +static const MemoryRegionOps tz_mpc_mem_blocked_ops = {
> +    .read_with_attrs = tz_mpc_mem_blocked_read,
> +    .write_with_attrs = tz_mpc_mem_blocked_write,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +    .valid.min_access_size = 1,
> +    .valid.max_access_size = 8,
> +    .impl.min_access_size = 1,
> +    .impl.max_access_size = 8,
> +};
> +
> +static IOMMUTLBEntry tz_mpc_translate(IOMMUMemoryRegion *iommu,
> +                                      hwaddr addr, IOMMUAccessFlags flags,
> +                                      int iommu_idx)
> +{
> +    TZMPC *s = TZ_MPC(container_of(iommu, TZMPC, upstream));
> +    bool ok;
> +
> +    IOMMUTLBEntry ret = {
> +        .iova = addr & ~(s->blocksize - 1),
> +        .translated_addr = addr & ~(s->blocksize - 1),
> +        .addr_mask = s->blocksize - 1,
> +        .perm = IOMMU_RW,
> +    };
> +
> +    /* Look at the per-block configuration for this address, and
> +     * return a TLB entry directing the transaction at either
> +     * downstream_as or blocked_io_as, as appropriate.
> +     * For the moment, always permit accesses.
> +     */
> +    ok = true;
> +
> +    trace_tz_mpc_translate(addr, flags,
> +                           iommu_idx == IOMMU_IDX_S ? "S" : "NS",
> +                           ok ? "pass" : "block");
> +
> +    ret.target_as = ok ? &s->downstream_as : &s->blocked_io_as;
> +    return ret;
> +}
> +
> +static int tz_mpc_attrs_to_index(IOMMUMemoryRegion *iommu, MemTxAttrs attrs)
> +{
> +    /* We treat unspecified attributes like secure. Transactions with
> +     * unspecified attributes come from places like
> +     * cpu_physical_memory_write_rom() for initial image load, and we want
> +     * those to pass through the from-reset "everything is secure" config.
> +     * All the real during-emulation transactions from the CPU will
> +     * specify attributes.
> +     */
> +    return (attrs.unspecified || attrs.secure) ? IOMMU_IDX_S : IOMMU_IDX_NS;
> +}
> +
> +static int tz_mpc_num_indexes(IOMMUMemoryRegion *iommu)
> +{
> +    return IOMMU_NUM_INDEXES;
> +}
> +
> +static void tz_mpc_reset(DeviceState *dev)
> +{
> +}
> +
> +static void tz_mpc_init(Object *obj)
> +{
> +    DeviceState *dev = DEVICE(obj);
> +    TZMPC *s = TZ_MPC(obj);
> +
> +    qdev_init_gpio_out_named(dev, &s->irq, "irq", 1);
> +}
> +
> +static void tz_mpc_realize(DeviceState *dev, Error **errp)
> +{
> +    Object *obj = OBJECT(dev);
> +    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
> +    TZMPC *s = TZ_MPC(dev);
> +    uint64_t size;
> +
> +    /* We can't create the upstream end of the port until realize,
> +     * as we don't know the size of the MR used as the downstream until then.
> +     * We insist on having a downstream, to avoid complicating the code
> +     * with handling the "don't know how big this is" case. It's easy
> +     * enough for the user to create an unimplemented_device as downstream
> +     * if they have nothing else to plug into this.
> +     */
> +    if (!s->downstream) {
> +        error_setg(errp, "MPC 'downstream' link not set");
> +        return;
> +    }
> +
> +    size = memory_region_size(s->downstream);
> +
> +    memory_region_init_iommu(&s->upstream, sizeof(s->upstream),
> +                             TYPE_TZ_MPC_IOMMU_MEMORY_REGION,
> +                             obj, "tz-mpc-upstream", size);
> +
> +    /* In real hardware the block size is configurable. In QEMU we could
> +     * make it configurable but will need it to be at least as big as the
> +     * target page size so we can execute out of the resulting MRs. Guest
> +     * software is supposed to check the block size using the BLK_CFG
> +     * register, so make it fixed at the page size.
> +     */
> +    s->blocksize = memory_region_iommu_get_min_page_size(&s->upstream);
> +    if (size % s->blocksize != 0) {
> +        error_setg(errp,
> +                   "MPC 'downstream' size %" PRId64
> +                   " is not a multiple of %" HWADDR_PRIx " bytes",
> +                   size, s->blocksize);
> +        object_unref(OBJECT(&s->upstream));
> +        return;
> +    }
> +
> +    /* BLK_MAX is the max value of BLK_IDX, which indexes an array of 32-bit
> +     * words, each bit of which indicates one block.
> +     */
> +    s->blk_max = DIV_ROUND_UP(size / s->blocksize, 32);
> +
> +    memory_region_init_io(&s->regmr, obj, &tz_mpc_reg_ops,
> +                          s, "tz-mpc-regs", 0x1000);
> +    sysbus_init_mmio(sbd, &s->regmr);
> +
> +    sysbus_init_mmio(sbd, MEMORY_REGION(&s->upstream));
> +
> +    /* This memory region is not exposed to users of this device as a
> +     * sysbus MMIO region, but is instead used internally as something
> +     * that our IOMMU translate function might direct accesses to.
> +     */
> +    memory_region_init_io(&s->blocked_io, obj, &tz_mpc_mem_blocked_ops,
> +                          s, "tz-mpc-blocked-io", size);
> +
> +    address_space_init(&s->downstream_as, s->downstream,
> +                       "tz-mpc-downstream");
> +    address_space_init(&s->blocked_io_as, &s->blocked_io,
> +                       "tz-mpc-blocked-io");
> +}
> +
> +static const VMStateDescription tz_mpc_vmstate = {
> +    .name = "tz-mpc",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +static Property tz_mpc_properties[] = {
> +    DEFINE_PROP_LINK("downstream", TZMPC, downstream,
> +                     TYPE_MEMORY_REGION, MemoryRegion *),
> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
> +static void tz_mpc_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    dc->realize = tz_mpc_realize;
> +    dc->vmsd = &tz_mpc_vmstate;
> +    dc->reset = tz_mpc_reset;
> +    dc->props = tz_mpc_properties;
> +}
> +
> +static const TypeInfo tz_mpc_info = {
> +    .name = TYPE_TZ_MPC,
> +    .parent = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(TZMPC),
> +    .instance_init = tz_mpc_init,
> +    .class_init = tz_mpc_class_init,
> +};
> +
> +static void tz_mpc_iommu_memory_region_class_init(ObjectClass *klass,
> +                                                  void *data)
> +{
> +    IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass);
> +
> +    imrc->translate = tz_mpc_translate;
> +    imrc->attrs_to_index = tz_mpc_attrs_to_index;
> +    imrc->num_indexes = tz_mpc_num_indexes;
> +}
> +
> +static const TypeInfo tz_mpc_iommu_memory_region_info = {
> +    .name = TYPE_TZ_MPC_IOMMU_MEMORY_REGION,
> +    .parent = TYPE_IOMMU_MEMORY_REGION,
> +    .class_init = tz_mpc_iommu_memory_region_class_init,
> +};
> +
> +static void tz_mpc_register_types(void)
> +{
> +    type_register_static(&tz_mpc_info);
> +    type_register_static(&tz_mpc_iommu_memory_region_info);
> +}
> +
> +type_init(tz_mpc_register_types);
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 1823f900b9..9cddb699df 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -449,6 +449,8 @@ F: hw/char/cmsdk-apb-uart.c
>  F: include/hw/char/cmsdk-apb-uart.h
>  F: hw/misc/tz-ppc.c
>  F: include/hw/misc/tz-ppc.h
> +F: hw/misc/tz-mpc.c
> +F: include/hw/misc/tz-mpc.h
>
>  ARM cores
>  M: Peter Maydell <peter.maydell@linaro.org>
> diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
> index dd29e741c2..30e73847ac 100644
> --- a/default-configs/arm-softmmu.mak
> +++ b/default-configs/arm-softmmu.mak
> @@ -106,6 +106,7 @@ CONFIG_CMSDK_APB_UART=y
>  CONFIG_MPS2_FPGAIO=y
>  CONFIG_MPS2_SCC=y
>
> +CONFIG_TZ_MPC=y
>  CONFIG_TZ_PPC=y
>  CONFIG_IOTKIT=y
>  CONFIG_IOTKIT_SECCTL=y
> diff --git a/hw/misc/trace-events b/hw/misc/trace-events
> index 562d9ed005..d4835c8970 100644
> --- a/hw/misc/trace-events
> +++ b/hw/misc/trace-events
> @@ -84,6 +84,13 @@ mos6522_set_sr_int(void) "set sr_int"
>  mos6522_write(uint64_t addr, uint64_t val) "reg=0x%"PRIx64 " val=0x%"PRIx64
>  mos6522_read(uint64_t addr, unsigned val) "reg=0x%"PRIx64 " val=0x%x"
>
> +# hw/misc/tz-mpc.c
> +tz_mpc_reg_read(uint32_t offset, uint64_t data, unsigned size) "TZ MPC regs read: offset 0x%x data 0x%" PRIx64 " size %u"
> +tz_mpc_reg_write(uint32_t offset, uint64_t data, unsigned size) "TZ MPC regs write: offset 0x%x data 0x%" PRIx64 " size %u"
> +tz_mpc_mem_blocked_read(uint64_t addr, unsigned size, bool secure) "TZ MPC blocked read: offset 0x%" PRIx64 " size %u secure %d"
> +tz_mpc_mem_blocked_write(uint64_t addr, uint64_t data, unsigned size, bool secure) "TZ MPC blocked write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d"
> +tz_mpc_translate(uint64_t addr, int flags, const char *idx, const char *res) "TZ MPC translate: addr 0x%" PRIx64 " flags 0x%x iommu_idx %s: %s"
> +
>  # hw/misc/tz-ppc.c
>  tz_ppc_reset(void) "TZ PPC: reset"
>  tz_ppc_cfg_nonsec(int n, int level) "TZ PPC: cfg_nonsec[%d] = %d"


--
Alex Bennée

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 19/27] hw/misc/tz-mpc.c: Implement registers
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 19/27] hw/misc/tz-mpc.c: Implement registers Peter Maydell
@ 2018-05-23 10:44   ` Alex Bennée
  0 siblings, 0 replies; 114+ messages in thread
From: Alex Bennée @ 2018-05-23 10:44 UTC (permalink / raw)
  To: Peter Maydell
  Cc: qemu-arm, qemu-devel, patches, Paolo Bonzini, Richard Henderson


Peter Maydell <peter.maydell@linaro.org> writes:

> Implement the missing registers for the TZ MPC.
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  include/hw/misc/tz-mpc.h |  10 +++
>  hw/misc/tz-mpc.c         | 137 ++++++++++++++++++++++++++++++++++++++-
>  2 files changed, 144 insertions(+), 3 deletions(-)
>
> diff --git a/include/hw/misc/tz-mpc.h b/include/hw/misc/tz-mpc.h
> index b5eaf1699e..1fff4d6029 100644
> --- a/include/hw/misc/tz-mpc.h
> +++ b/include/hw/misc/tz-mpc.h
> @@ -48,6 +48,16 @@ struct TZMPC {
>
>      /*< public >*/
>
> +    /* State */
> +    uint32_t ctrl;
> +    uint32_t blk_idx;
> +    uint32_t int_stat;
> +    uint32_t int_en;
> +    uint32_t int_info1;
> +    uint32_t int_info2;
> +
> +    uint32_t *blk_lut;
> +
>      qemu_irq irq;
>
>      /* Properties */
> diff --git a/hw/misc/tz-mpc.c b/hw/misc/tz-mpc.c
> index d4467ccc3b..93453cbef2 100644
> --- a/hw/misc/tz-mpc.c
> +++ b/hw/misc/tz-mpc.c
> @@ -28,16 +28,23 @@ enum {
>
>  /* Config registers */
>  REG32(CTRL, 0x00)
> +    FIELD(CTRL, SEC_RESP, 4, 1)
> +    FIELD(CTRL, AUTOINC, 8, 1)
> +    FIELD(CTRL, LOCKDOWN, 31, 1)
>  REG32(BLK_MAX, 0x10)
>  REG32(BLK_CFG, 0x14)
>  REG32(BLK_IDX, 0x18)
>  REG32(BLK_LUT, 0x1c)
>  REG32(INT_STAT, 0x20)
> +    FIELD(INT_STAT, IRQ, 0, 1)
>  REG32(INT_CLEAR, 0x24)
> +    FIELD(INT_CLEAR, IRQ, 0, 1)
>  REG32(INT_EN, 0x28)
> +    FIELD(INT_EN, IRQ, 0, 1)
>  REG32(INT_INFO1, 0x2c)
>  REG32(INT_INFO2, 0x30)
>  REG32(INT_SET, 0x34)
> +    FIELD(INT_SET, IRQ, 0, 1)
>  REG32(PIDR4, 0xfd0)
>  REG32(PIDR5, 0xfd4)
>  REG32(PIDR6, 0xfd8)
> @@ -57,14 +64,55 @@ static const uint8_t tz_mpc_idregs[] = {
>      0x0d, 0xf0, 0x05, 0xb1,
>  };
>
> +static void tz_mpc_irq_update(TZMPC *s)
> +{
> +    qemu_set_irq(s->irq, s->int_stat && s->int_en);
> +}
> +
>  static MemTxResult tz_mpc_reg_read(void *opaque, hwaddr addr,
>                                     uint64_t *pdata,
>                                     unsigned size, MemTxAttrs attrs)
>  {
> +    TZMPC *s = TZ_MPC(opaque);
>      uint64_t r;
>      uint32_t offset = addr & ~0x3;
>
>      switch (offset) {
> +    case A_CTRL:
> +        r = s->ctrl;
> +        break;
> +    case A_BLK_MAX:
> +        r = s->blk_max;
> +        break;
> +    case A_BLK_CFG:
> +        /* We are never in "init in progress state", so this just indicates
> +         * the block size. s->blocksize == (1 << BLK_CFG + 5), so
> +         * BLK_CFG == ctz32(s->blocksize) - 5
> +         */
> +        r = ctz32(s->blocksize) - 5;
> +        break;
> +    case A_BLK_IDX:
> +        r = s->blk_idx;
> +        break;
> +    case A_BLK_LUT:
> +        r = s->blk_lut[s->blk_idx];
> +        if (size == 4) {
> +            s->blk_idx++;
> +            s->blk_idx %= s->blk_max;
> +        }
> +        break;
> +    case A_INT_STAT:
> +        r = s->int_stat;
> +        break;
> +    case A_INT_EN:
> +        r = s->int_en;
> +        break;
> +    case A_INT_INFO1:
> +        r = s->int_info1;
> +        break;
> +    case A_INT_INFO2:
> +        r = s->int_info2;
> +        break;
>      case A_PIDR4:
>      case A_PIDR5:
>      case A_PIDR6:
> @@ -110,6 +158,7 @@ static MemTxResult tz_mpc_reg_write(void *opaque, hwaddr addr,
>                                      uint64_t value,
>                                      unsigned size, MemTxAttrs attrs)
>  {
> +    TZMPC *s = TZ_MPC(opaque);
>      uint32_t offset = addr & ~0x3;
>
>      trace_tz_mpc_reg_write(addr, value, size);
> @@ -122,9 +171,15 @@ static MemTxResult tz_mpc_reg_write(void *opaque, hwaddr addr,
>          uint32_t oldval;
>
>          switch (offset) {
> -            /* As we add support for registers which need expansions
> -             * other than zeroes we'll fill in cases here.
> -             */
> +        case A_CTRL:
> +            oldval = s->ctrl;
> +            break;
> +        case A_BLK_IDX:
> +            oldval = s->blk_idx;
> +            break;
> +        case A_BLK_LUT:
> +            oldval = s->blk_lut[s->blk_idx];
> +            break;
>          default:
>              oldval = 0;
>              break;
> @@ -132,7 +187,51 @@ static MemTxResult tz_mpc_reg_write(void *opaque, hwaddr addr,
>          value = deposit32(oldval, (addr & 3) * 8, size * 8, value);
>      }
>
> +    if ((s->ctrl & R_CTRL_LOCKDOWN_MASK) &&
> +        (offset == A_CTRL || offset == A_BLK_LUT || offset == A_INT_EN)) {
> +        /* Lockdown mode makes these three registers read-only, and
> +         * the only way out of it is to reset the device.
> +         */
> +        qemu_log_mask(LOG_GUEST_ERROR, "TZ MPC register write to offset 0x%x "
> +                      "while MPC is in lockdown mode\n", offset);
> +        return MEMTX_OK;
> +    }
> +
>      switch (offset) {
> +    case A_CTRL:
> +        /* We don't implement the 'data gating' feature so all other bits
> +         * are reserved and we make them RAZ/WI.
> +         */
> +        s->ctrl = value & (R_CTRL_SEC_RESP_MASK |
> +                           R_CTRL_AUTOINC_MASK |
> +                           R_CTRL_LOCKDOWN_MASK);
> +        break;
> +    case A_BLK_IDX:
> +        s->blk_idx = value % s->blk_max;
> +        break;
> +    case A_BLK_LUT:
> +        s->blk_lut[s->blk_idx] = value;
> +        if (size == 4) {
> +            s->blk_idx++;
> +            s->blk_idx %= s->blk_max;
> +        }
> +        break;
> +    case A_INT_CLEAR:
> +        if (value & R_INT_CLEAR_IRQ_MASK) {
> +            s->int_stat = 0;
> +            tz_mpc_irq_update(s);
> +        }
> +        break;
> +    case A_INT_EN:
> +        s->int_en = value & R_INT_EN_IRQ_MASK;
> +        tz_mpc_irq_update(s);
> +        break;
> +    case A_INT_SET:
> +        if (value & R_INT_SET_IRQ_MASK) {
> +            s->int_stat = R_INT_STAT_IRQ_MASK;
> +            tz_mpc_irq_update(s);
> +        }
> +        break;
>      case A_PIDR4:
>      case A_PIDR5:
>      case A_PIDR6:
> @@ -248,6 +347,16 @@ static int tz_mpc_num_indexes(IOMMUMemoryRegion *iommu)
>
>  static void tz_mpc_reset(DeviceState *dev)
>  {
> +    TZMPC *s = TZ_MPC(dev);
> +
> +    s->ctrl = 0;

According to the spec the reset for CTRL is 0x100

> +    s->blk_idx = 0;
> +    s->int_stat = 0;
> +    s->int_en = 0;

the reset for INT_EN is 0x1

> +    s->int_info1 = 0;
> +    s->int_info2 = 0;
> +
> +    memset(s->blk_lut, 0, s->blk_max * sizeof(uint32_t));
>  }
>
>  static void tz_mpc_init(Object *obj)
> @@ -321,13 +430,35 @@ static void tz_mpc_realize(DeviceState *dev, Error **errp)
>                         "tz-mpc-downstream");
>      address_space_init(&s->blocked_io_as, &s->blocked_io,
>                         "tz-mpc-blocked-io");
> +
> +    s->blk_lut = g_new(uint32_t, s->blk_max);
> +}
> +
> +static int tz_mpc_post_load(void *opaque, int version_id)
> +{
> +    TZMPC *s = TZ_MPC(opaque);
> +
> +    /* Check the incoming data doesn't point blk_idx off the end of blk_lut. */
> +    if (s->blk_idx >= s->blk_max) {
> +        return -1;
> +    }
> +    return 0;
>  }
>
>  static const VMStateDescription tz_mpc_vmstate = {
>      .name = "tz-mpc",
>      .version_id = 1,
>      .minimum_version_id = 1,
> +    .post_load = tz_mpc_post_load,
>      .fields = (VMStateField[]) {
> +        VMSTATE_UINT32(ctrl, TZMPC),
> +        VMSTATE_UINT32(blk_idx, TZMPC),
> +        VMSTATE_UINT32(int_stat, TZMPC),
> +        VMSTATE_UINT32(int_en, TZMPC),
> +        VMSTATE_UINT32(int_info1, TZMPC),
> +        VMSTATE_UINT32(int_info2, TZMPC),
> +        VMSTATE_VARRAY_UINT32(blk_lut, TZMPC, blk_max,
> +                              0, vmstate_info_uint32, uint32_t),
>          VMSTATE_END_OF_LIST()
>      }
>  };


--
Alex Bennée

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 20/27] hw/misc/tz-mpc.c: Implement correct blocked-access behaviour
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 20/27] hw/misc/tz-mpc.c: Implement correct blocked-access behaviour Peter Maydell
@ 2018-05-23 10:49   ` Alex Bennée
  2018-05-23 11:54     ` Peter Maydell
  0 siblings, 1 reply; 114+ messages in thread
From: Alex Bennée @ 2018-05-23 10:49 UTC (permalink / raw)
  To: Peter Maydell
  Cc: qemu-arm, qemu-devel, patches, Paolo Bonzini, Richard Henderson


Peter Maydell <peter.maydell@linaro.org> writes:

> The MPC is guest-configurable for whether blocked accesses:
>  * should be RAZ/WI or cause a bus error
>  * should generate an interrupt or not
>
> Implement this behaviour in the blocked-access handlers.
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  hw/misc/tz-mpc.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 48 insertions(+), 2 deletions(-)
>
> diff --git a/hw/misc/tz-mpc.c b/hw/misc/tz-mpc.c
> index 93453cbef2..39a72563b7 100644
> --- a/hw/misc/tz-mpc.c
> +++ b/hw/misc/tz-mpc.c
> @@ -43,6 +43,9 @@ REG32(INT_EN, 0x28)
>      FIELD(INT_EN, IRQ, 0, 1)
>  REG32(INT_INFO1, 0x2c)
>  REG32(INT_INFO2, 0x30)
> +    FIELD(INT_INFO2, HMASTER, 0, 16)
> +    FIELD(INT_INFO2, HNONSEC, 16, 1)
> +    FIELD(INT_INFO2, CFG_NS, 17, 1)
>  REG32(INT_SET, 0x34)
>      FIELD(INT_SET, IRQ, 0, 1)
>  REG32(PIDR4, 0xfd0)
> @@ -266,6 +269,45 @@ static const MemoryRegionOps tz_mpc_reg_ops = {
>      .impl.max_access_size = 4,
>  };
>
> +static inline bool tz_mpc_cfg_ns(TZMPC *s, hwaddr addr)
> +{
> +    /* Return the cfg_ns bit from the LUT for the specified address */
> +    hwaddr blknum = addr / s->blocksize;
> +    hwaddr blkword = blknum / 32;
> +    uint32_t blkbit = 1U << (blknum % 32);
> +
> +    /* This would imply the address was larger than the size we
> +     * defined this memory region to be, so it can't happen.
> +     */
> +    assert(blkword < s->blk_max);
> +    return s->blk_lut[blkword] & blkbit;
> +}
> +
> +static MemTxResult tz_mpc_handle_block(TZMPC *s, hwaddr addr, MemTxAttrs attrs)
> +{
> +    /* Handle a blocked transaction: raise IRQ, capture info, etc */
> +    if (!s->int_stat) {
> +        /* First blocked transfer: capture information into INT_INFO1 and
> +         * INT_INFO2. Subsequent transfers are still blocked but don't
> +         * capture information until the guest clears the interrupt.
> +         */
> +
> +        s->int_info1 = addr;
> +        s->int_info2 = 0;
> +        s->int_info2 = FIELD_DP32(s->int_info2, INT_INFO2, HMASTER,
> +                                  attrs.requester_id & 0xffff);

Does this actually need masking given the source is a 16 bit wide bitfield?

> +        s->int_info2 = FIELD_DP32(s->int_info2, INT_INFO2, HNONSEC,
> +                                  ~attrs.secure);
> +        s->int_info2 = FIELD_DP32(s->int_info2, INT_INFO2, CFG_NS,
> +                                  tz_mpc_cfg_ns(s, addr));
> +        s->int_stat |= R_INT_STAT_IRQ_MASK;
> +        tz_mpc_irq_update(s);
> +    }
> +
> +    /* Generate bus error if desired; otherwise RAZ/WI */
> +    return (s->ctrl & R_CTRL_SEC_RESP_MASK) ? MEMTX_ERROR : MEMTX_OK;
> +}
> +
>  /* Accesses only reach these read and write functions if the MPC is
>   * blocking them; non-blocked accesses go directly to the downstream
>   * memory region without passing through this code.
> @@ -274,19 +316,23 @@ static MemTxResult tz_mpc_mem_blocked_read(void *opaque, hwaddr addr,
>                                             uint64_t *pdata,
>                                             unsigned size, MemTxAttrs attrs)
>  {
> +    TZMPC *s = TZ_MPC(opaque);
> +
>      trace_tz_mpc_mem_blocked_read(addr, size, attrs.secure);
>
>      *pdata = 0;
> -    return MEMTX_OK;
> +    return tz_mpc_handle_block(s, addr, attrs);
>  }
>
>  static MemTxResult tz_mpc_mem_blocked_write(void *opaque, hwaddr addr,
>                                              uint64_t value,
>                                              unsigned size, MemTxAttrs attrs)
>  {
> +    TZMPC *s = TZ_MPC(opaque);
> +
>      trace_tz_mpc_mem_blocked_write(addr, value, size, attrs.secure);
>
> -    return MEMTX_OK;
> +    return tz_mpc_handle_block(s, addr, attrs);
>  }
>
>  static const MemoryRegionOps tz_mpc_mem_blocked_ops = {


--
Alex Bennée

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 22/27] vmstate.h: Provide VMSTATE_BOOL_SUB_ARRAY
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 22/27] vmstate.h: Provide VMSTATE_BOOL_SUB_ARRAY Peter Maydell
@ 2018-05-23 11:01   ` Alex Bennée
  0 siblings, 0 replies; 114+ messages in thread
From: Alex Bennée @ 2018-05-23 11:01 UTC (permalink / raw)
  To: Peter Maydell
  Cc: qemu-arm, qemu-devel, patches, Paolo Bonzini, Richard Henderson


Peter Maydell <peter.maydell@linaro.org> writes:

> Provide a VMSTATE_BOOL_SUB_ARRAY to go with VMSTATE_UINT8_SUB_ARRAY
> and friends.
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

> ---
>  include/migration/vmstate.h | 3 +++
>  1 file changed, 3 insertions(+)
>
> diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
> index df463fd33d..59fc75e418 100644
> --- a/include/migration/vmstate.h
> +++ b/include/migration/vmstate.h
> @@ -870,6 +870,9 @@ extern const VMStateInfo vmstate_info_qtailq;
>  #define VMSTATE_BOOL_ARRAY(_f, _s, _n)                               \
>      VMSTATE_BOOL_ARRAY_V(_f, _s, _n, 0)
>
> +#define VMSTATE_BOOL_SUB_ARRAY(_f, _s, _start, _num)                \
> +    VMSTATE_SUB_ARRAY(_f, _s, _start, _num, 0, vmstate_info_bool, bool)
> +
>  #define VMSTATE_UINT16_ARRAY_V(_f, _s, _n, _v)                         \
>      VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_uint16, uint16_t)


--
Alex Bennée

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 25/27] hw/arm/iotkit: Instantiate MPC
  2018-05-21 14:04 ` [Qemu-devel] [PATCH 25/27] hw/arm/iotkit: Instantiate MPC Peter Maydell
@ 2018-05-23 11:38   ` Alex Bennée
  0 siblings, 0 replies; 114+ messages in thread
From: Alex Bennée @ 2018-05-23 11:38 UTC (permalink / raw)
  To: Peter Maydell
  Cc: qemu-arm, qemu-devel, patches, Paolo Bonzini, Richard Henderson


Peter Maydell <peter.maydell@linaro.org> writes:

> Wire up the one MPC that is part of the IoTKit itself. For the
> moment we don't wire up its interrupt line.
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

> ---
>  include/hw/arm/iotkit.h |  2 ++
>  hw/arm/iotkit.c         | 38 +++++++++++++++++++++++++++-----------
>  2 files changed, 29 insertions(+), 11 deletions(-)
>
> diff --git a/include/hw/arm/iotkit.h b/include/hw/arm/iotkit.h
> index c6129d926b..b21cf1ab9d 100644
> --- a/include/hw/arm/iotkit.h
> +++ b/include/hw/arm/iotkit.h
> @@ -51,6 +51,7 @@
>  #include "hw/arm/armv7m.h"
>  #include "hw/misc/iotkit-secctl.h"
>  #include "hw/misc/tz-ppc.h"
> +#include "hw/misc/tz-mpc.h"
>  #include "hw/timer/cmsdk-apb-timer.h"
>  #include "hw/misc/unimp.h"
>  #include "hw/or-irq.h"
> @@ -74,6 +75,7 @@ typedef struct IoTKit {
>      IoTKitSecCtl secctl;
>      TZPPC apb_ppc0;
>      TZPPC apb_ppc1;
> +    TZMPC mpc;
>      CMSDKAPBTIMER timer0;
>      CMSDKAPBTIMER timer1;
>      qemu_or_irq ppc_irq_orgate;
> diff --git a/hw/arm/iotkit.c b/hw/arm/iotkit.c
> index 234185e8f7..160e40c744 100644
> --- a/hw/arm/iotkit.c
> +++ b/hw/arm/iotkit.c
> @@ -130,6 +130,7 @@ static void iotkit_init(Object *obj)
>                        TYPE_TZ_PPC);
>      init_sysbus_child(obj, "apb-ppc1", &s->apb_ppc1, sizeof(s->apb_ppc1),
>                        TYPE_TZ_PPC);
> +    init_sysbus_child(obj, "mpc", &s->mpc, sizeof(s->mpc), TYPE_TZ_MPC);
>      init_sysbus_child(obj, "timer0", &s->timer0, sizeof(s->timer0),
>                        TYPE_CMSDK_APB_TIMER);
>      init_sysbus_child(obj, "timer1", &s->timer1, sizeof(s->timer1),
> @@ -266,15 +267,6 @@ static void iotkit_realize(DeviceState *dev, Error **errp)
>       */
>      make_alias(s, &s->alias3, "alias 3", 0x50000000, 0x10000000, 0x40000000);
>
> -    /* This RAM should be behind a Memory Protection Controller, but we
> -     * don't implement that yet.
> -     */
> -    memory_region_init_ram(&s->sram0, NULL, "iotkit.sram0", 0x00008000, &err);
> -    if (err) {
> -        error_propagate(errp, err);
> -        return;
> -    }
> -    memory_region_add_subregion(&s->container, 0x20000000, &s->sram0);
>
>      /* Security controller */
>      object_property_set_bool(OBJECT(&s->secctl), true, "realized", &err);
> @@ -310,6 +302,32 @@ static void iotkit_realize(DeviceState *dev, Error **errp)
>      qdev_connect_gpio_out_named(dev_secctl, "sec_resp_cfg", 0,
>                                  qdev_get_gpio_in(dev_splitter, 0));
>
> +    /* This RAM lives behind the Memory Protection Controller */
> +    memory_region_init_ram(&s->sram0, NULL, "iotkit.sram0", 0x00008000, &err);
> +    if (err) {
> +        error_propagate(errp, err);
> +        return;
> +    }
> +    object_property_set_link(OBJECT(&s->mpc), OBJECT(&s->sram0),
> +                             "downstream", &err);
> +    if (err) {
> +        error_propagate(errp, err);
> +        return;
> +    }
> +    object_property_set_bool(OBJECT(&s->mpc), true, "realized", &err);
> +    if (err) {
> +        error_propagate(errp, err);
> +        return;
> +    }
> +    /* Map the upstream end of the MPC into the right place... */
> +    memory_region_add_subregion(&s->container, 0x20000000,
> +                                sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->mpc),
> +                                                       1));
> +    /* ...and its register interface */
> +    memory_region_add_subregion(&s->container, 0x50083000,
> +                                sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->mpc),
> +                                                       0));
> +
>      /* Devices behind APB PPC0:
>       *   0x40000000: timer0
>       *   0x40001000: timer1
> @@ -473,8 +491,6 @@ static void iotkit_realize(DeviceState *dev, Error **errp)
>      create_unimplemented_device("NS watchdog", 0x40081000, 0x1000);
>      create_unimplemented_device("S watchdog", 0x50081000, 0x1000);
>
> -    create_unimplemented_device("SRAM0 MPC", 0x50083000, 0x1000);
> -
>      for (i = 0; i < ARRAY_SIZE(s->ppc_irq_splitter); i++) {
>          Object *splitter = OBJECT(&s->ppc_irq_splitter[i]);


--
Alex Bennée

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 26/27] hw/arm/iotkit: Wire up MPC interrupt lines
  2018-05-21 14:04 ` [Qemu-devel] [PATCH 26/27] hw/arm/iotkit: Wire up MPC interrupt lines Peter Maydell
@ 2018-05-23 11:39   ` Alex Bennée
  0 siblings, 0 replies; 114+ messages in thread
From: Alex Bennée @ 2018-05-23 11:39 UTC (permalink / raw)
  To: Peter Maydell
  Cc: qemu-arm, qemu-devel, patches, Paolo Bonzini, Richard Henderson


Peter Maydell <peter.maydell@linaro.org> writes:

> The interrupt outputs from the MPC in the IoTKit and the expansion
> MPCs in the board must be wired up to the security controller, and
> also all ORed together to produce a single line to the NVIC.
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

> ---
>  include/hw/arm/iotkit.h |  6 ++++
>  hw/arm/iotkit.c         | 74 +++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 80 insertions(+)
>
> diff --git a/include/hw/arm/iotkit.h b/include/hw/arm/iotkit.h
> index b21cf1ab9d..2cddde55dd 100644
> --- a/include/hw/arm/iotkit.h
> +++ b/include/hw/arm/iotkit.h
> @@ -42,6 +42,9 @@
>   *  + named GPIO outputs ahb_ppcexp{0,1,2,3}_irq_enable
>   *  + named GPIO outputs ahb_ppcexp{0,1,2,3}_irq_clear
>   *  + named GPIO inputs ahb_ppcexp{0,1,2,3}_irq_status
> + * Controlling each of the 16 expansion MPCs which a system using the IoTKit
> + * might provide:
> + *  + named GPIO inputs mpcexp_status[0..15]
>   */
>
>  #ifndef IOTKIT_H
> @@ -81,6 +84,8 @@ typedef struct IoTKit {
>      qemu_or_irq ppc_irq_orgate;
>      SplitIRQ sec_resp_splitter;
>      SplitIRQ ppc_irq_splitter[NUM_PPCS];
> +    SplitIRQ mpc_irq_splitter[IOTS_NUM_EXP_MPC + IOTS_NUM_MPC];
> +    qemu_or_irq mpc_irq_orgate;
>
>      UnimplementedDeviceState dualtimer;
>      UnimplementedDeviceState s32ktimer;
> @@ -99,6 +104,7 @@ typedef struct IoTKit {
>      qemu_irq nsc_cfg_in;
>
>      qemu_irq irq_status_in[NUM_EXTERNAL_PPCS];
> +    qemu_irq mpcexp_status_in[IOTS_NUM_EXP_MPC];
>
>      uint32_t nsccfg;
>
> diff --git a/hw/arm/iotkit.c b/hw/arm/iotkit.c
> index 160e40c744..133d5bb34f 100644
> --- a/hw/arm/iotkit.c
> +++ b/hw/arm/iotkit.c
> @@ -131,6 +131,18 @@ static void iotkit_init(Object *obj)
>      init_sysbus_child(obj, "apb-ppc1", &s->apb_ppc1, sizeof(s->apb_ppc1),
>                        TYPE_TZ_PPC);
>      init_sysbus_child(obj, "mpc", &s->mpc, sizeof(s->mpc), TYPE_TZ_MPC);
> +    object_initialize(&s->mpc_irq_orgate, sizeof(s->mpc_irq_orgate),
> +                      TYPE_OR_IRQ);
> +    object_property_add_child(obj, "mpc-irq-orgate",
> +                              OBJECT(&s->mpc_irq_orgate), &error_abort);
> +    for (i = 0; i < ARRAY_SIZE(s->mpc_irq_splitter); i++) {
> +        char *name = g_strdup_printf("mpc-irq-splitter-%d", i);
> +        SplitIRQ *splitter = &s->mpc_irq_splitter[i];
> +
> +        object_initialize(splitter, sizeof(*splitter), TYPE_SPLIT_IRQ);
> +        object_property_add_child(obj, name, OBJECT(splitter), &error_abort);
> +        g_free(name);
> +    }
>      init_sysbus_child(obj, "timer0", &s->timer0, sizeof(s->timer0),
>                        TYPE_CMSDK_APB_TIMER);
>      init_sysbus_child(obj, "timer1", &s->timer1, sizeof(s->timer1),
> @@ -163,6 +175,12 @@ static void iotkit_exp_irq(void *opaque, int n, int level)
>      qemu_set_irq(s->exp_irqs[n], level);
>  }
>
> +static void iotkit_mpcexp_status(void *opaque, int n, int level)
> +{
> +    IoTKit *s = IOTKIT(opaque);
> +    qemu_set_irq(s->mpcexp_status_in[n], level);
> +}
> +
>  static void iotkit_realize(DeviceState *dev, Error **errp)
>  {
>      IoTKit *s = IOTKIT(dev);
> @@ -328,6 +346,22 @@ static void iotkit_realize(DeviceState *dev, Error **errp)
>                                  sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->mpc),
>                                                         0));
>
> +    /* We must OR together lines from the MPC splitters to go to the NVIC */
> +    object_property_set_int(OBJECT(&s->mpc_irq_orgate),
> +                            IOTS_NUM_EXP_MPC + IOTS_NUM_MPC, "num-lines", &err);
> +    if (err) {
> +        error_propagate(errp, err);
> +        return;
> +    }
> +    object_property_set_bool(OBJECT(&s->mpc_irq_orgate), true,
> +                             "realized", &err);
> +    if (err) {
> +        error_propagate(errp, err);
> +        return;
> +    }
> +    qdev_connect_gpio_out(DEVICE(&s->mpc_irq_orgate), 0,
> +                          qdev_get_gpio_in(DEVICE(&s->armv7m), 9));
> +
>      /* Devices behind APB PPC0:
>       *   0x40000000: timer0
>       *   0x40001000: timer1
> @@ -536,6 +570,46 @@ static void iotkit_realize(DeviceState *dev, Error **errp)
>          g_free(gpioname);
>      }
>
> +    /* Wire up the splitters for the MPC IRQs */
> +    for (i = 0; i < IOTS_NUM_EXP_MPC + IOTS_NUM_MPC; i++) {
> +        SplitIRQ *splitter = &s->mpc_irq_splitter[i];
> +        DeviceState *dev_splitter = DEVICE(splitter);
> +
> +        object_property_set_int(OBJECT(splitter), 2, "num-lines", &err);
> +        if (err) {
> +            error_propagate(errp, err);
> +            return;
> +        }
> +        object_property_set_bool(OBJECT(splitter), true, "realized", &err);
> +        if (err) {
> +            error_propagate(errp, err);
> +            return;
> +        }
> +
> +        if (i < IOTS_NUM_EXP_MPC) {
> +            /* Splitter input is from GPIO input line */
> +            s->mpcexp_status_in[i] = qdev_get_gpio_in(dev_splitter, 0);
> +            qdev_connect_gpio_out(dev_splitter, 0,
> +                                  qdev_get_gpio_in_named(dev_secctl,
> +                                                         "mpcexp_status", i));
> +        } else {
> +            /* Splitter input is from our own MPC */
> +            qdev_connect_gpio_out_named(DEVICE(&s->mpc), "irq", 0,
> +                                        qdev_get_gpio_in(dev_splitter, 0));
> +            qdev_connect_gpio_out(dev_splitter, 0,
> +                                  qdev_get_gpio_in_named(dev_secctl,
> +                                                         "mpc_status", 0));
> +        }
> +
> +        qdev_connect_gpio_out(dev_splitter, 1,
> +                              qdev_get_gpio_in(DEVICE(&s->mpc_irq_orgate), i));
> +    }
> +    /* Create GPIO inputs which will pass the line state for our
> +     * mpcexp_irq inputs to the correct splitter devices.
> +     */
> +    qdev_init_gpio_in_named(dev, iotkit_mpcexp_status, "mpcexp_status",
> +                            IOTS_NUM_EXP_MPC);
> +
>      iotkit_forward_sec_resp_cfg(s);
>
>      system_clock_scale = NANOSECONDS_PER_SECOND / s->mainclk_frq;


--
Alex Bennée

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 27/27] hw/arm/mps2-tz.c: Instantiate MPCs
  2018-05-21 14:04 ` [Qemu-devel] [PATCH 27/27] hw/arm/mps2-tz.c: Instantiate MPCs Peter Maydell
@ 2018-05-23 11:41   ` Alex Bennée
  0 siblings, 0 replies; 114+ messages in thread
From: Alex Bennée @ 2018-05-23 11:41 UTC (permalink / raw)
  To: Peter Maydell
  Cc: qemu-arm, qemu-devel, patches, Paolo Bonzini, Richard Henderson


Peter Maydell <peter.maydell@linaro.org> writes:

> Instantiate and wire up the Memory Protection Controllers
> in the MPS2 board itself.
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

> ---
>  hw/arm/mps2-tz.c | 71 ++++++++++++++++++++++++++++++------------------
>  1 file changed, 44 insertions(+), 27 deletions(-)
>
> diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c
> index 8dc8bfd4ab..a58b5dea79 100644
> --- a/hw/arm/mps2-tz.c
> +++ b/hw/arm/mps2-tz.c
> @@ -44,6 +44,7 @@
>  #include "hw/timer/cmsdk-apb-timer.h"
>  #include "hw/misc/mps2-scc.h"
>  #include "hw/misc/mps2-fpgaio.h"
> +#include "hw/misc/tz-mpc.h"
>  #include "hw/arm/iotkit.h"
>  #include "hw/devices.h"
>  #include "net/net.h"
> @@ -64,13 +65,12 @@ typedef struct {
>
>      IoTKit iotkit;
>      MemoryRegion psram;
> -    MemoryRegion ssram1;
> +    MemoryRegion ssram[3];
>      MemoryRegion ssram1_m;
> -    MemoryRegion ssram23;
>      MPS2SCC scc;
>      MPS2FPGAIO fpgaio;
>      TZPPC ppc[5];
> -    UnimplementedDeviceState ssram_mpc[3];
> +    TZMPC ssram_mpc[3];
>      UnimplementedDeviceState spi[5];
>      UnimplementedDeviceState i2c[4];
>      UnimplementedDeviceState i2s_audio;
> @@ -95,16 +95,6 @@ typedef struct {
>  /* Main SYSCLK frequency in Hz */
>  #define SYSCLK_FRQ 20000000
>
> -/* Initialize the auxiliary RAM region @mr and map it into
> - * the memory map at @base.
> - */
> -static void make_ram(MemoryRegion *mr, const char *name,
> -                     hwaddr base, hwaddr size)
> -{
> -    memory_region_init_ram(mr, NULL, name, size, &error_fatal);
> -    memory_region_add_subregion(get_system_memory(), base, mr);
> -}
> -
>  /* Create an alias of an entire original MemoryRegion @orig
>   * located at @base in the memory map.
>   */
> @@ -224,6 +214,44 @@ static MemoryRegion *make_fpgaio(MPS2TZMachineState *mms, void *opaque,
>      return sysbus_mmio_get_region(SYS_BUS_DEVICE(fpgaio), 0);
>  }
>
> +static MemoryRegion *make_mpc(MPS2TZMachineState *mms, void *opaque,
> +                              const char *name, hwaddr size)
> +{
> +    TZMPC *mpc = opaque;
> +    int i = mpc - &mms->ssram_mpc[0];
> +    MemoryRegion *ssram = &mms->ssram[i];
> +    MemoryRegion *upstream;
> +    char *mpcname = g_strdup_printf("%s-mpc", name);
> +    static uint32_t ramsize[] = { 0x00400000, 0x00200000, 0x00200000 };
> +    static uint32_t rambase[] = { 0x00000000, 0x28000000, 0x28200000 };
> +
> +    memory_region_init_ram(ssram, NULL, name, ramsize[i], &error_fatal);
> +
> +    init_sysbus_child(OBJECT(mms), mpcname, mpc,
> +                      sizeof(mms->ssram_mpc[0]), TYPE_TZ_MPC);
> +    object_property_set_link(OBJECT(mpc), OBJECT(ssram),
> +                             "downstream", &error_fatal);
> +    object_property_set_bool(OBJECT(mpc), true, "realized", &error_fatal);
> +    /* Map the upstream end of the MPC into system memory */
> +    upstream = sysbus_mmio_get_region(SYS_BUS_DEVICE(mpc), 1);
> +    memory_region_add_subregion(get_system_memory(), rambase[i], upstream);
> +    /* and connect its interrupt to the IoTKit */
> +    qdev_connect_gpio_out_named(DEVICE(mpc), "irq", 0,
> +                                qdev_get_gpio_in_named(DEVICE(&mms->iotkit),
> +                                                       "mpcexp_status", i));
> +
> +    /* The first SSRAM is a special case as it has an alias; accesses to
> +     * the alias region at 0x00400000 must also go to the MPC upstream.
> +     */
> +    if (i == 0) {
> +        make_ram_alias(&mms->ssram1_m, "mps.ssram1_m", upstream, 0x00400000);
> +    }
> +
> +    g_free(mpcname);
> +    /* Return the register interface MR for our caller to map behind the PPC */
> +    return sysbus_mmio_get_region(SYS_BUS_DEVICE(mpc), 0);
> +}
> +
>  static void mps2tz_common_init(MachineState *machine)
>  {
>      MPS2TZMachineState *mms = MPS2TZ_MACHINE(machine);
> @@ -285,14 +313,6 @@ static void mps2tz_common_init(MachineState *machine)
>                                           NULL, "mps.ram", 0x01000000);
>      memory_region_add_subregion(system_memory, 0x80000000, &mms->psram);
>
> -    /* The SSRAM memories should all be behind Memory Protection Controllers,
> -     * but we don't implement that yet.
> -     */
> -    make_ram(&mms->ssram1, "mps.ssram1", 0x00000000, 0x00400000);
> -    make_ram_alias(&mms->ssram1_m, "mps.ssram1_m", &mms->ssram1, 0x00400000);
> -
> -    make_ram(&mms->ssram23, "mps.ssram23", 0x28000000, 0x00400000);
> -
>      /* The overflow IRQs for all UARTs are ORed together.
>       * Tx, Rx and "combined" IRQs are sent to the NVIC separately.
>       * Create the OR gate for this.
> @@ -322,12 +342,9 @@ static void mps2tz_common_init(MachineState *machine)
>      const PPCInfo ppcs[] = { {
>              .name = "apb_ppcexp0",
>              .ports = {
> -                { "ssram-mpc0", make_unimp_dev, &mms->ssram_mpc[0],
> -                  0x58007000, 0x1000 },
> -                { "ssram-mpc1", make_unimp_dev, &mms->ssram_mpc[1],
> -                  0x58008000, 0x1000 },
> -                { "ssram-mpc2", make_unimp_dev, &mms->ssram_mpc[2],
> -                  0x58009000, 0x1000 },
> +                { "ssram-0", make_mpc, &mms->ssram_mpc[0], 0x58007000, 0x1000 },
> +                { "ssram-1", make_mpc, &mms->ssram_mpc[1], 0x58008000, 0x1000 },
> +                { "ssram-2", make_mpc, &mms->ssram_mpc[2], 0x58009000, 0x1000 },
>              },
>          }, {
>              .name = "apb_ppcexp1",


--
Alex Bennée

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 14/27] iommu: Add IOMMU index concept to IOMMU API
  2018-05-23  1:06           ` Peter Xu
@ 2018-05-23 11:47             ` Peter Maydell
  2018-05-24  6:23               ` Peter Xu
  0 siblings, 1 reply; 114+ messages in thread
From: Peter Maydell @ 2018-05-23 11:47 UTC (permalink / raw)
  To: Peter Xu
  Cc: qemu-arm, QEMU Developers, Paolo Bonzini, Richard Henderson,
	Alex Bennée, patches, David Gibson, Alex Williamson

On 23 May 2018 at 02:06, Peter Xu <peterx@redhat.com> wrote:
> On Tue, May 22, 2018 at 12:11:38PM +0100, Peter Maydell wrote:
>> On 22 May 2018 at 12:02, Peter Xu <peterx@redhat.com> wrote:
>> > On Tue, May 22, 2018 at 09:40:44AM +0100, Peter Maydell wrote:

>> > And if we see current implementation for this (still, I copied code
>> > from other patch in the series to here to ease discussion):
>> >
>> > @@ -498,8 +498,15 @@ static MemoryRegionSection address_space_translate_iommu(IOMMUMemoryRegion *iomm
>> >      do {
>> >          hwaddr addr = *xlat;
>> >          IOMMUMemoryRegionClass *imrc = memory_region_get_iommu_class_nocheck(iommu_mr);
>> > -        IOMMUTLBEntry iotlb = imrc->translate(iommu_mr, addr, is_write ?
>> > -                                              IOMMU_WO : IOMMU_RO);
>> > +        int iommu_idx = 0;
>> > +        IOMMUTLBEntry iotlb;
>> > +
>> > +        if (imrc->attrs_to_index) {
>> > +            iommu_idx = imrc->attrs_to_index(iommu_mr, attrs);
>> > +        }
>> > +
>> > +        iotlb = imrc->translate(iommu_mr, addr, is_write ?
>> > +                                IOMMU_WO : IOMMU_RO, iommu_idx);
>> >
>> > Here what if we pass attrs directly into imrc->translate() and just
>> > call imrc->attrs_to_index() inside the arch-dependent translate()
>> > function?  Will that work too?
>>
>> You don't always have the attributes at the point where you want
>> to call translate. (For instance, memory_region_notify_iommu()
>> doesn't have attributes.)
>>
>> I started off with "pass the tx attrs into the translate method",
>> which is fine for the code flows which are actually doing
>> memory transactions, but breaks down when you try to incorporate
>> notifiers.
>
> Could you elaborate a bit more on why IOMMU notifier failed to
> corporate when passing in MemTxAttrs?  I am not sure I caught the idea
> here, but can we copy the MemTxAttrs into IOMMUTLBEntry when
> translating, then in IOMMU notifiers we can know the attrs (if that is
> what MPC wants)?

(1) The notifier API lets you register a notifier before you've
called the translate API
(2) An IOMMUTLBEntry can be valid for more than just the txattrs
that it was passed in (for instance, if an IOMMU doesn't care
about txattrs at all, then the resulting TLB entry is valid for
any txattrs; or if the IOMMU only cares about attrs.secure the
resulting TLB entries are valid for both attrs.user=0 and
attrs.user=1).
(3) when the IOMMU calls the notifier because the guest config
changed it doesn't have tx attributes, so it would have to
fabricate some; and the guest config will invalidate transactions
with some combinations of tx attributes and not others.

As Paolo pointed out you could also implement this by rather
of having an iommu_index concept, instead having some kind
of "here is a mask of which txattrs fields matter, and here's
another parameter with which txattrs fields are affected".
That makes it awkward though to implement "txattrs.unspecified
acts like txattrs.secure == 1" type behaviour, though, which is
easy with an index abstraction layer. It also would be harder
to implement the default 'replay' method, I think.

Plus I think that handling this the same way TCG does is a
reasonable approach -- we know that it's a usefully flexible
concept.

>> > I had a quick glance at the series, I have no thorough idea on the
>> > whole stuff, but I'd say some of the patches are exactly what I wanted
>> > if to support MemTxAttrs in VT-d emulation one day (now DMAR of VT-d
>> > is bypassing MemTxAttrs and IMHO that's incorrect).  If we can somehow
>> > pass in the MemTxAttrs then that'll be perfect and I can continue to
>> > work on that.  If we pass in iommu_idx now instead, it would take some
>> > time for me to figure out how to further achieve the same goal for
>> > VT-d in the future, e.g., I would still want to pass in MemTxAttrs,
>> > but that's obviously duplicated with iommu_idx.
>>
>> The idea is that you should never need to pass in the MemTxAttrs,
>> because everything that the IOMMU might care about in the tx attrs
>> must be encoded into the iommu index. (The point where the IOMMU
>> gets to do that encoding is in its attrs_to_index() method.)
>
> For the DMAR issue I would care about MemTxAttrs.requester_id.  Just
> to confirm - do you mean I encode the 16bits field into iommu_idx too,
> or is there any smarter way to do so?  Asked since otherwise iommu_idx
> will gradually grow into another MemTxAttrs to me.

It will only need to do so for IOMMUs that care about that field.

(See also the other thread with Eric Auger talking about
maybe caring about requester_id like that. Needing to look
at requester_id is an area I haven't thought too much about,
and it is a bit of an odd one because it's a much larger
space than any of the other parts of the txattrs. In some
cases it ought to be possible to say "requester_id lets
us determine an iommu index, and there are a lot fewer
than 2^16 actual iommu indexes because a lot of the requestor_id
values indicate the same actual iommu translation", I suspect.)

thanks
-- PMM

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 17/27] exec.c: Handle IOMMUs in address_space_translate_for_iotlb()
  2018-05-23  9:51   ` Alex Bennée
@ 2018-05-23 11:52     ` Peter Maydell
  2018-05-24 19:54     ` Auger Eric
  1 sibling, 0 replies; 114+ messages in thread
From: Peter Maydell @ 2018-05-23 11:52 UTC (permalink / raw)
  To: Alex Bennée
  Cc: qemu-arm, QEMU Developers, patches, Paolo Bonzini, Richard Henderson

On 23 May 2018 at 10:51, Alex Bennée <alex.bennee@linaro.org> wrote:
>
> Peter Maydell <peter.maydell@linaro.org> writes:
>
>> Currently we don't support board configurations that put an IOMMU
>> in the path of the CPU's memory transactions, and instead just
>> assert() if the memory region fonud in address_space_translate_for_iotlb()
>> is an IOMMUMemoryRegion.
>>
>> Remove this limitation by having the function handle IOMMUs.
>> This is mostly straightforward, but we must make sure we have
>> a notifier registered for every IOMMU that a transaction has
>> passed through, so that we can flush the TLB appropriately
>> when any of the IOMMUs change their mappings.
>>
>> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
>> ---
>>  include/exec/exec-all.h |   3 +-
>>  include/qom/cpu.h       |   3 +
>>  accel/tcg/cputlb.c      |   3 +-
>>  exec.c                  | 147 +++++++++++++++++++++++++++++++++++++++-
>>  4 files changed, 152 insertions(+), 4 deletions(-)
>>
>> diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
>> index 4d09eaba72..e0ff19b711 100644
>> --- a/include/exec/exec-all.h
>> +++ b/include/exec/exec-all.h
>> @@ -469,7 +469,8 @@ void tb_flush_jmp_cache(CPUState *cpu, target_ulong addr);
>>
>>  MemoryRegionSection *
>>  address_space_translate_for_iotlb(CPUState *cpu, int asidx, hwaddr addr,
>> -                                  hwaddr *xlat, hwaddr *plen);
>> +                                  hwaddr *xlat, hwaddr *plen,
>> +                                  MemTxAttrs attrs, int *prot);
>>  hwaddr memory_region_section_get_iotlb(CPUState *cpu,
>>                                         MemoryRegionSection *section,
>>                                         target_ulong vaddr,
>> diff --git a/include/qom/cpu.h b/include/qom/cpu.h
>> index 9d3afc6c75..d4a30149dd 100644
>> --- a/include/qom/cpu.h
>> +++ b/include/qom/cpu.h
>> @@ -429,6 +429,9 @@ struct CPUState {
>>      uint16_t pending_tlb_flush;
>>
>>      int hvf_fd;
>> +
>> +    /* track IOMMUs whose translations we've cached in the TCG TLB */
>> +    GSList *iommu_notifiers;
>
> So we are only concerned about TCG IOMMU notifiers here, specifically
> TCGIOMMUNotifier structures. Why not just use a GArray and save
> ourselves chasing pointers?

I don't have a strong opinion about which data structure to use;
but GSList has a "find an entry" API and GArray doesn't, so I
picked the one that had the API that meant I didn't need to
hand-code a search loop.

>> --- a/exec.c
>> +++ b/exec.c
>> @@ -650,18 +650,158 @@ MemoryRegion *flatview_translate(FlatView *fv, hwaddr addr, hwaddr *xlat,
>>      return mr;
>>  }
>>
>> +typedef struct TCGIOMMUNotifier {
>> +    IOMMUNotifier n;
>> +    MemoryRegion *mr;
>> +    CPUState *cpu;
>
> This seems superfluous if we are storing the list of notifiers in the CPUState

You need it because in the notifier callback all you get is a pointer
to the IOMMUNotifier, and we need to get from there to the CPUState*.

>> +    int iommu_idx;
>> +    bool active;
>> +} TCGIOMMUNotifier;

thanks
-- PMM

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 20/27] hw/misc/tz-mpc.c: Implement correct blocked-access behaviour
  2018-05-23 10:49   ` Alex Bennée
@ 2018-05-23 11:54     ` Peter Maydell
  0 siblings, 0 replies; 114+ messages in thread
From: Peter Maydell @ 2018-05-23 11:54 UTC (permalink / raw)
  To: Alex Bennée
  Cc: qemu-arm, QEMU Developers, patches, Paolo Bonzini, Richard Henderson

On 23 May 2018 at 11:49, Alex Bennée <alex.bennee@linaro.org> wrote:
>
> Peter Maydell <peter.maydell@linaro.org> writes:
>
>> The MPC is guest-configurable for whether blocked accesses:
>>  * should be RAZ/WI or cause a bus error
>>  * should generate an interrupt or not
>>
>> Implement this behaviour in the blocked-access handlers.
>>
>> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
>> ---
>>  hw/misc/tz-mpc.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++--
>>  1 file changed, 48 insertions(+), 2 deletions(-)
>>
>> diff --git a/hw/misc/tz-mpc.c b/hw/misc/tz-mpc.c
>> index 93453cbef2..39a72563b7 100644
>> --- a/hw/misc/tz-mpc.c
>> +++ b/hw/misc/tz-mpc.c
>> @@ -43,6 +43,9 @@ REG32(INT_EN, 0x28)
>>      FIELD(INT_EN, IRQ, 0, 1)
>>  REG32(INT_INFO1, 0x2c)
>>  REG32(INT_INFO2, 0x30)
>> +    FIELD(INT_INFO2, HMASTER, 0, 16)
>> +    FIELD(INT_INFO2, HNONSEC, 16, 1)
>> +    FIELD(INT_INFO2, CFG_NS, 17, 1)
>>  REG32(INT_SET, 0x34)
>>      FIELD(INT_SET, IRQ, 0, 1)
>>  REG32(PIDR4, 0xfd0)
>> @@ -266,6 +269,45 @@ static const MemoryRegionOps tz_mpc_reg_ops = {
>>      .impl.max_access_size = 4,
>>  };
>>
>> +static inline bool tz_mpc_cfg_ns(TZMPC *s, hwaddr addr)
>> +{
>> +    /* Return the cfg_ns bit from the LUT for the specified address */
>> +    hwaddr blknum = addr / s->blocksize;
>> +    hwaddr blkword = blknum / 32;
>> +    uint32_t blkbit = 1U << (blknum % 32);
>> +
>> +    /* This would imply the address was larger than the size we
>> +     * defined this memory region to be, so it can't happen.
>> +     */
>> +    assert(blkword < s->blk_max);
>> +    return s->blk_lut[blkword] & blkbit;
>> +}
>> +
>> +static MemTxResult tz_mpc_handle_block(TZMPC *s, hwaddr addr, MemTxAttrs attrs)
>> +{
>> +    /* Handle a blocked transaction: raise IRQ, capture info, etc */
>> +    if (!s->int_stat) {
>> +        /* First blocked transfer: capture information into INT_INFO1 and
>> +         * INT_INFO2. Subsequent transfers are still blocked but don't
>> +         * capture information until the guest clears the interrupt.
>> +         */
>> +
>> +        s->int_info1 = addr;
>> +        s->int_info2 = 0;
>> +        s->int_info2 = FIELD_DP32(s->int_info2, INT_INFO2, HMASTER,
>> +                                  attrs.requester_id & 0xffff);
>
> Does this actually need masking given the source is a 16 bit wide bitfield?

That might change in future (eg Eric was talking about wanting
to put SMMUv3 substream IDs in transaction attributes, and those
are 20 bits wide, so we might want to widen requester_id to fit them).

thanks
-- PMM

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 14/27] iommu: Add IOMMU index concept to IOMMU API
  2018-05-23 11:47             ` Peter Maydell
@ 2018-05-24  6:23               ` Peter Xu
  2018-05-24 10:54                 ` Peter Maydell
  0 siblings, 1 reply; 114+ messages in thread
From: Peter Xu @ 2018-05-24  6:23 UTC (permalink / raw)
  To: Peter Maydell
  Cc: qemu-arm, QEMU Developers, Paolo Bonzini, Richard Henderson,
	Alex Bennée, patches, David Gibson, Alex Williamson

On Wed, May 23, 2018 at 12:47:16PM +0100, Peter Maydell wrote:
> On 23 May 2018 at 02:06, Peter Xu <peterx@redhat.com> wrote:
> > On Tue, May 22, 2018 at 12:11:38PM +0100, Peter Maydell wrote:
> >> On 22 May 2018 at 12:02, Peter Xu <peterx@redhat.com> wrote:
> >> > On Tue, May 22, 2018 at 09:40:44AM +0100, Peter Maydell wrote:
> 
> >> > And if we see current implementation for this (still, I copied code
> >> > from other patch in the series to here to ease discussion):
> >> >
> >> > @@ -498,8 +498,15 @@ static MemoryRegionSection address_space_translate_iommu(IOMMUMemoryRegion *iomm
> >> >      do {
> >> >          hwaddr addr = *xlat;
> >> >          IOMMUMemoryRegionClass *imrc = memory_region_get_iommu_class_nocheck(iommu_mr);
> >> > -        IOMMUTLBEntry iotlb = imrc->translate(iommu_mr, addr, is_write ?
> >> > -                                              IOMMU_WO : IOMMU_RO);
> >> > +        int iommu_idx = 0;
> >> > +        IOMMUTLBEntry iotlb;
> >> > +
> >> > +        if (imrc->attrs_to_index) {
> >> > +            iommu_idx = imrc->attrs_to_index(iommu_mr, attrs);
> >> > +        }
> >> > +
> >> > +        iotlb = imrc->translate(iommu_mr, addr, is_write ?
> >> > +                                IOMMU_WO : IOMMU_RO, iommu_idx);
> >> >
> >> > Here what if we pass attrs directly into imrc->translate() and just
> >> > call imrc->attrs_to_index() inside the arch-dependent translate()
> >> > function?  Will that work too?
> >>
> >> You don't always have the attributes at the point where you want
> >> to call translate. (For instance, memory_region_notify_iommu()
> >> doesn't have attributes.)
> >>
> >> I started off with "pass the tx attrs into the translate method",
> >> which is fine for the code flows which are actually doing
> >> memory transactions, but breaks down when you try to incorporate
> >> notifiers.
> >
> > Could you elaborate a bit more on why IOMMU notifier failed to
> > corporate when passing in MemTxAttrs?  I am not sure I caught the idea
> > here, but can we copy the MemTxAttrs into IOMMUTLBEntry when
> > translating, then in IOMMU notifiers we can know the attrs (if that is
> > what MPC wants)?
> 
> (1) The notifier API lets you register a notifier before you've
> called the translate API

Yes.

> (2) An IOMMUTLBEntry can be valid for more than just the txattrs
> that it was passed in (for instance, if an IOMMU doesn't care
> about txattrs at all, then the resulting TLB entry is valid for
> any txattrs; or if the IOMMU only cares about attrs.secure the
> resulting TLB entries are valid for both attrs.user=0 and
> attrs.user=1).

[1]

Yes exactly, that's why I thought copying the txattrs into IOTLB
should work.

> (3) when the IOMMU calls the notifier because the guest config
> changed it doesn't have tx attributes, so it would have to
> fabricate some; and the guest config will invalidate transactions
> with some combinations of tx attributes and not others.

IMHO it doesn't directly matter with what we are discussing now.  That
IOMMU_NOTIFIER_[UN]MAP flag tells what kind of message would the
notifier be interested in from "what kind of mapping it is".  IMHO
it's not really related to some other attributes when translation
happens - in our case, it does not directly related to what txattrs
value is.  Here as mentioned at [1] above IMHO we can still check this
against txattrs in the notifier handler, then we ignore messages that
we don't care about.  Actually the IOMMU_NOTIFIER_[UN]MAP flags can be
removed and we can just do similar things (e.g., we can skip MAP
messages if we only care about UNMAP messages), but since it's a
general concept and easy to be generalized, so we provided these
MAP/UNMAP flags to ease the notifier hooks.

In other words, I think we can also add more flags for SECURE or not.
However I still don't see a reason (from above three points) on why we
can't pass in txattrs directly into translate(), and at the same time
we copy the txattrs into IOTLB so that IOMMUTLBEntry can contain some
context information. [2]

> 
> As Paolo pointed out you could also implement this by rather
> of having an iommu_index concept, instead having some kind
> of "here is a mask of which txattrs fields matter, and here's
> another parameter with which txattrs fields are affected".
> That makes it awkward though to implement "txattrs.unspecified
> acts like txattrs.secure == 1" type behaviour, though, which is
> easy with an index abstraction layer. It also would be harder
> to implement the default 'replay' method, I think.

Please refer to my above comment at [2] - I am still confused on why
we must use this iommu_idx concept.  How about we just introduce
IOMMU_NOTIFIER_SECURE (or something similar) and let TCG code register
with that?  Though for the rest of notifiers we'll need to touch up
too to make sure all existing notifiers will still receive all the
message, no matter whether it's secure or not.

I'd also appreciate if you could paste me the link for Paolo's
message, since I cannot find it.

> 
> Plus I think that handling this the same way TCG does is a
> reasonable approach -- we know that it's a usefully flexible
> concept.
> 
> >> > I had a quick glance at the series, I have no thorough idea on the
> >> > whole stuff, but I'd say some of the patches are exactly what I wanted
> >> > if to support MemTxAttrs in VT-d emulation one day (now DMAR of VT-d
> >> > is bypassing MemTxAttrs and IMHO that's incorrect).  If we can somehow
> >> > pass in the MemTxAttrs then that'll be perfect and I can continue to
> >> > work on that.  If we pass in iommu_idx now instead, it would take some
> >> > time for me to figure out how to further achieve the same goal for
> >> > VT-d in the future, e.g., I would still want to pass in MemTxAttrs,
> >> > but that's obviously duplicated with iommu_idx.
> >>
> >> The idea is that you should never need to pass in the MemTxAttrs,
> >> because everything that the IOMMU might care about in the tx attrs
> >> must be encoded into the iommu index. (The point where the IOMMU
> >> gets to do that encoding is in its attrs_to_index() method.)
> >
> > For the DMAR issue I would care about MemTxAttrs.requester_id.  Just
> > to confirm - do you mean I encode the 16bits field into iommu_idx too,
> > or is there any smarter way to do so?  Asked since otherwise iommu_idx
> > will gradually grow into another MemTxAttrs to me.
> 
> It will only need to do so for IOMMUs that care about that field.
> 
> (See also the other thread with Eric Auger talking about
> maybe caring about requester_id like that. Needing to look
> at requester_id is an area I haven't thought too much about,
> and it is a bit of an odd one because it's a much larger
> space than any of the other parts of the txattrs. In some
> cases it ought to be possible to say "requester_id lets
> us determine an iommu index, and there are a lot fewer
> than 2^16 actual iommu indexes because a lot of the requestor_id
> values indicate the same actual iommu translation", I suspect.)

AFAIK requester_id will only be the same in very rare cases, for
example, when multiple PCI devices (no matter whether it's PCI or
PCIe) are under the same PCIe-to-PCI bridge, then all these devices
will use the bridge's requester ID as their own.  In most cases, each
PCIe device will have their own unique requester ID.  So it'll be
common that requester ID number can be at least equal to the number of
devices.

Thanks,

-- 
Peter Xu

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 14/27] iommu: Add IOMMU index concept to IOMMU API
  2018-05-24  6:23               ` Peter Xu
@ 2018-05-24 10:54                 ` Peter Maydell
  2018-05-25  2:50                   ` Peter Xu
  2018-05-25  9:27                   ` Auger Eric
  0 siblings, 2 replies; 114+ messages in thread
From: Peter Maydell @ 2018-05-24 10:54 UTC (permalink / raw)
  To: Peter Xu
  Cc: qemu-arm, QEMU Developers, Paolo Bonzini, Richard Henderson,
	Alex Bennée, patches, David Gibson, Alex Williamson

On 24 May 2018 at 07:23, Peter Xu <peterx@redhat.com> wrote:
> On Wed, May 23, 2018 at 12:47:16PM +0100, Peter Maydell wrote:
>> On 23 May 2018 at 02:06, Peter Xu <peterx@redhat.com> wrote:
>> > Could you elaborate a bit more on why IOMMU notifier failed to
>> > corporate when passing in MemTxAttrs?  I am not sure I caught the idea
>> > here, but can we copy the MemTxAttrs into IOMMUTLBEntry when
>> > translating, then in IOMMU notifiers we can know the attrs (if that is
>> > what MPC wants)?
>>
>> (1) The notifier API lets you register a notifier before you've
>> called the translate API
>
> Yes.
>
>> (2) An IOMMUTLBEntry can be valid for more than just the txattrs
>> that it was passed in (for instance, if an IOMMU doesn't care
>> about txattrs at all, then the resulting TLB entry is valid for
>> any txattrs; or if the IOMMU only cares about attrs.secure the
>> resulting TLB entries are valid for both attrs.user=0 and
>> attrs.user=1).
>
> [1]
>
> Yes exactly, that's why I thought copying the txattrs into IOTLB
> should work.

I'm a bit confused about why the IOMMUTLBEntry is relevant here.
That's the thing returned from the translate method, so there's
no point in copying txattrs into it, because the caller by definition
already had them. At the point where the IOMMU notices a guest
changed the config, it doesn't have an IOMMUTLBEntry or a set of
tx attrs.

>> (3) when the IOMMU calls the notifier because the guest config
>> changed it doesn't have tx attributes, so it would have to
>> fabricate some; and the guest config will invalidate transactions
>> with some combinations of tx attributes and not others.
>
> IMHO it doesn't directly matter with what we are discussing now.  That
> IOMMU_NOTIFIER_[UN]MAP flag tells what kind of message would the
> notifier be interested in from "what kind of mapping it is".  IMHO
> it's not really related to some other attributes when translation
> happens - in our case, it does not directly related to what txattrs
> value is.  Here as mentioned at [1] above IMHO we can still check this
> against txattrs in the notifier handler, then we ignore messages that
> we don't care about.  Actually the IOMMU_NOTIFIER_[UN]MAP flags can be
> removed and we can just do similar things (e.g., we can skip MAP
> messages if we only care about UNMAP messages), but since it's a
> general concept and easy to be generalized, so we provided these
> MAP/UNMAP flags to ease the notifier hooks.
>
> In other words, I think we can also add more flags for SECURE or not.
> However I still don't see a reason (from above three points) on why we
> can't pass in txattrs directly into translate(), and at the same time
> we copy the txattrs into IOTLB so that IOMMUTLBEntry can contain some
> context information. [2]

I'm afraid I really don't understand the design you're proposing
here. But overall I think the point of divergence is that
the mapping from "transaction attributes" to "translation contexts"
(ie, effectively different page tables) is not 1:1. So for instance:

Our current IOMMUs which don't care about txattrs:

  [any txattr at all] -> the one and only translation context

An IOMMU which cares about attrs.secure, and also treats
attrs.unspecified like secure:
  [any txattr with attrs.secure = 1]  \-> 'secure' context'
  MEMATTRS_UNSPECIFIED                /

  [txattrs with secure = 1] -> 'nonsecure' context

An IOMMU which cares about attrs.secure and attrs.user:
  [secure=1,user=1]   -> 'secure user' context
  [secure=0,user=1]   -> 'ns user' context
  [secure=1,user=0]   -> 's priv' context
  [secure=0,user=0]   -> 'ns priv' context

The IOMMU index captures this idea that there is not a 1:1
mapping, so we have a way to think about and refer to the
actual set of translation contexts that the IOMMU has.

>> As Paolo pointed out you could also implement this by rather
>> of having an iommu_index concept, instead having some kind
>> of "here is a mask of which txattrs fields matter, and here's
>> another parameter with which txattrs fields are affected".
>> That makes it awkward though to implement "txattrs.unspecified
>> acts like txattrs.secure == 1" type behaviour, though, which is
>> easy with an index abstraction layer. It also would be harder
>> to implement the default 'replay' method, I think.
>
> Please refer to my above comment at [2] - I am still confused on why
> we must use this iommu_idx concept.  How about we just introduce
> IOMMU_NOTIFIER_SECURE (or something similar) and let TCG code register
> with that?  Though for the rest of notifiers we'll need to touch up
> too to make sure all existing notifiers will still receive all the
> message, no matter whether it's secure or not.

I think I would definitely prefer not to have the secure/nonsecure
specific thing in the API. We've got good experience with TCG
where we abstract away the specifics of what an MMU cares about
into an mmu_index, and I'd like to keep that approach. Otherwise,
you immediately get into "and now we need to change the API again
to handle IOMMUs which care about attrs.user"; and then again
for attrs.requester_id; and now what about IOMMUs that care
about both secure and user... Better to have an abstraction so
that we don't need to keep changing the core code. In particular,
TCG doesn't know whether it's secure/nonsecure that matters -- that
is mostly handled by the target-specific parts, and TCG core code
just passes attributes around.

> I'd also appreciate if you could paste me the link for Paolo's
> message, since I cannot find it.

This is the one I had in mind:
https://lists.gnu.org/archive/html/qemu-devel/2018-05/msg03522.html

>> It will only need to do so for IOMMUs that care about that field.
>>
>> (See also the other thread with Eric Auger talking about
>> maybe caring about requester_id like that. Needing to look
>> at requester_id is an area I haven't thought too much about,
>> and it is a bit of an odd one because it's a much larger
>> space than any of the other parts of the txattrs. In some
>> cases it ought to be possible to say "requester_id lets
>> us determine an iommu index, and there are a lot fewer
>> than 2^16 actual iommu indexes because a lot of the requestor_id
>> values indicate the same actual iommu translation", I suspect.)
>
> AFAIK requester_id will only be the same in very rare cases, for
> example, when multiple PCI devices (no matter whether it's PCI or
> PCIe) are under the same PCIe-to-PCI bridge, then all these devices
> will use the bridge's requester ID as their own.  In most cases, each
> PCIe device will have their own unique requester ID.  So it'll be
> common that requester ID number can be at least equal to the number of
> devices.

I haven't looked at this, but my understanding is that at the moment
we do per-device requester_id by having each PCI device get its own
IOMMUMemoryRegion mapped into its address space. So we'd only need
to look at requester_id for the case of devices with multiple
subfunctions(?), and presumably most devices only have a handful
of those.

thanks
-- PMM

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 15/27] iommu: Add IOMMU index argument to notifier APIs
  2018-05-21 14:03 ` [Qemu-devel] [PATCH 15/27] iommu: Add IOMMU index argument to notifier APIs Peter Maydell
  2018-05-22 17:45   ` Richard Henderson
  2018-05-23  9:08   ` Alex Bennée
@ 2018-05-24 15:29   ` Auger Eric
  2018-05-24 17:03     ` Peter Maydell
  2 siblings, 1 reply; 114+ messages in thread
From: Auger Eric @ 2018-05-24 15:29 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel
  Cc: Paolo Bonzini, Richard Henderson, Alex Bennée, patches

Hi Peter,

On 05/21/2018 04:03 PM, Peter Maydell wrote:
> Add support for multiple IOMMU indexes to the IOMMU notifier APIs.
> When initializing a notifier with iommu_notifier_init(), the caller
> must pass the IOMMU index that it is interested in. When a change
> happens, the IOMMU implementation must pass
> memory_region_notify_iommu() the IOMMU index that has changed and
> that notifiers must be called for.
> 
> IOMMUs which support only a single index don't need to change.
> Callers which only really support working with IOMMUs with a single
> index can use the result of passing MEMTXATTRS_UNSPECIFIED to
> memory_region_iommu_attrs_to_index().
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  include/exec/memory.h    | 11 ++++++++++-
>  hw/i386/intel_iommu.c    |  4 ++--
>  hw/ppc/spapr_iommu.c     |  2 +-
>  hw/s390x/s390-pci-inst.c |  4 ++--
>  hw/vfio/common.c         |  6 +++++-
>  hw/virtio/vhost.c        |  7 ++++++-
>  memory.c                 |  8 +++++++-
>  7 files changed, 33 insertions(+), 9 deletions(-)
> 
> diff --git a/include/exec/memory.h b/include/exec/memory.h
> index f6226fb263..4e6b125add 100644
> --- a/include/exec/memory.h
> +++ b/include/exec/memory.h
> @@ -71,6 +71,7 @@ struct IOMMUTLBEntry {
>      hwaddr           iova;
>      hwaddr           translated_addr;
>      hwaddr           addr_mask;  /* 0xfff = 4k translation */
> +    int              iommu_idx;
I don't get why ne need iommu_idx field here. On translate the caller
has it. On notify the notifier has it?
>      IOMMUAccessFlags perm;
>  };
>  
> @@ -98,18 +99,21 @@ struct IOMMUNotifier {
>      /* Notify for address space range start <= addr <= end */
>      hwaddr start;
>      hwaddr end;
> +    int iommu_idx;
>      QLIST_ENTRY(IOMMUNotifier) node;
>  };
>  typedef struct IOMMUNotifier IOMMUNotifier;
>  
>  static inline void iommu_notifier_init(IOMMUNotifier *n, IOMMUNotify fn,
>                                         IOMMUNotifierFlag flags,
> -                                       hwaddr start, hwaddr end)
> +                                       hwaddr start, hwaddr end,
> +                                       int iommu_idx)
>  {
>      n->notify = fn;
>      n->notifier_flags = flags;
>      n->start = start;
>      n->end = end;
> +    n->iommu_idx = iommu_idx;
>  }
>  
>  /*
> @@ -323,7 +327,10 @@ typedef struct IOMMUMemoryRegionClass {
>       * Optional method: if this method is not provided, then
>       * memory_region_iommu_num_indexes() will return 1, indicating that
>       * only a single IOMMU index is supported.
> +     *
> +     * @iommu: the IOMMUMemoryRegion
>       */
> +    int (*num_indexes)(IOMMUMemoryRegion *iommu);
>  } IOMMUMemoryRegionClass;
>  
>  typedef struct CoalescedMemoryRange CoalescedMemoryRange;
> @@ -1028,11 +1035,13 @@ uint64_t memory_region_iommu_get_min_page_size(IOMMUMemoryRegion *iommu_mr);
>   * should be notified with an UNMAP followed by a MAP.
>   *
>   * @iommu_mr: the memory region that was changed
> + * @iommu_idx: the IOMMU index for the translation table which has changed
>   * @entry: the new entry in the IOMMU translation table.  The entry
>   *         replaces all old entries for the same virtual I/O address range.
>   *         Deleted entries have .@perm == 0.
>   */
>  void memory_region_notify_iommu(IOMMUMemoryRegion *iommu_mr,
> +                                int iommu_idx,
>                                  IOMMUTLBEntry entry);
>  
>  /**
> diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c
> index fb31de9416..b8c9354b0b 100644
> --- a/hw/i386/intel_iommu.c
> +++ b/hw/i386/intel_iommu.c
> @@ -1376,7 +1376,7 @@ static void vtd_iotlb_domain_invalidate(IntelIOMMUState *s, uint16_t domain_id)
>  static int vtd_page_invalidate_notify_hook(IOMMUTLBEntry *entry,
>                                             void *private)
>  {
> -    memory_region_notify_iommu((IOMMUMemoryRegion *)private, *entry);
> +    memory_region_notify_iommu((IOMMUMemoryRegion *)private, 0, *entry);
>      return 0;
>  }
>  
> @@ -1826,7 +1826,7 @@ static bool vtd_process_device_iotlb_desc(IntelIOMMUState *s,
>      entry.iova = addr;
>      entry.perm = IOMMU_NONE;
>      entry.translated_addr = 0;
> -    memory_region_notify_iommu(&vtd_dev_as->iommu, entry);
> +    memory_region_notify_iommu(&vtd_dev_as->iommu, 0, entry);
>  
>  done:
>      return true;
> diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c
> index aaa6010d5c..301708e45e 100644
> --- a/hw/ppc/spapr_iommu.c
> +++ b/hw/ppc/spapr_iommu.c
> @@ -428,7 +428,7 @@ static target_ulong put_tce_emu(sPAPRTCETable *tcet, target_ulong ioba,
>      entry.translated_addr = tce & page_mask;
>      entry.addr_mask = ~page_mask;
>      entry.perm = spapr_tce_iommu_access_flags(tce);
> -    memory_region_notify_iommu(&tcet->iommu, entry);
> +    memory_region_notify_iommu(&tcet->iommu, 0, entry);
>  
>      return H_SUCCESS;
>  }
> diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c
> index d1a5f79678..7b61367ee3 100644
> --- a/hw/s390x/s390-pci-inst.c
> +++ b/hw/s390x/s390-pci-inst.c
> @@ -589,7 +589,7 @@ static void s390_pci_update_iotlb(S390PCIIOMMU *iommu, S390IOTLBEntry *entry)
>              }
>  
>              notify.perm = IOMMU_NONE;
> -            memory_region_notify_iommu(&iommu->iommu_mr, notify);
> +            memory_region_notify_iommu(&iommu->iommu_mr, 0, notify);
>              notify.perm = entry->perm;
>          }
>  
> @@ -601,7 +601,7 @@ static void s390_pci_update_iotlb(S390PCIIOMMU *iommu, S390IOTLBEntry *entry)
>          g_hash_table_replace(iommu->iotlb, &cache->iova, cache);
>      }
>  
> -    memory_region_notify_iommu(&iommu->iommu_mr, notify);
> +    memory_region_notify_iommu(&iommu->iommu_mr, 0, notify);
>  }
>  
>  int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra)
> diff --git a/hw/vfio/common.c b/hw/vfio/common.c
> index 8e57265edf..fb396cf00a 100644
> --- a/hw/vfio/common.c
> +++ b/hw/vfio/common.c
> @@ -507,6 +507,7 @@ static void vfio_listener_region_add(MemoryListener *listener,
>      if (memory_region_is_iommu(section->mr)) {
>          VFIOGuestIOMMU *giommu;
>          IOMMUMemoryRegion *iommu_mr = IOMMU_MEMORY_REGION(section->mr);
> +        int iommu_idx;
>  
>          trace_vfio_listener_region_add_iommu(iova, end);
>          /*
> @@ -523,10 +524,13 @@ static void vfio_listener_region_add(MemoryListener *listener,
>          llend = int128_add(int128_make64(section->offset_within_region),
>                             section->size);
>          llend = int128_sub(llend, int128_one());
> +        iommu_idx = memory_region_iommu_attrs_to_index(iommu_mr,
> +                                                       MEMTXATTRS_UNSPECIFIED);
In that case VFIO ideally wants to be notified for any guest update
(whatever the page set) to reprogram the physical IOMMU corresponding
entries and doesn't want to register a notifier per iommu_idx. Also it
does not know which ones are supported. Is there a corresponding
iommu_idx value? MEMTXATTRS_ANY?

Thanks

Eric
>          iommu_notifier_init(&giommu->n, vfio_iommu_map_notify,
>                              IOMMU_NOTIFIER_ALL,
>                              section->offset_within_region,
> -                            int128_get64(llend));
> +                            int128_get64(llend),
> +                            iommu_idx);
>          QLIST_INSERT_HEAD(&container->giommu_list, giommu, giommu_next);
>  
>          memory_region_register_iommu_notifier(section->mr, &giommu->n);
> diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
> index 48f4fd7cc9..6218df7683 100644
> --- a/hw/virtio/vhost.c
> +++ b/hw/virtio/vhost.c
> @@ -657,6 +657,8 @@ static void vhost_iommu_region_add(MemoryListener *listener,
>                                           iommu_listener);
>      struct vhost_iommu *iommu;
>      Int128 end;
> +    int iommu_idx;
> +    IOMMUMemoryRegion *iommu_mr = IOMMU_MEMORY_REGION(section->mr);
>  
>      if (!memory_region_is_iommu(section->mr)) {
>          return;
> @@ -666,10 +668,13 @@ static void vhost_iommu_region_add(MemoryListener *listener,
>      end = int128_add(int128_make64(section->offset_within_region),
>                       section->size);
>      end = int128_sub(end, int128_one());
> +    iommu_idx = memory_region_iommu_attrs_to_index(iommu_mr,
> +                                                   MEMTXATTRS_UNSPECIFIED);
>      iommu_notifier_init(&iommu->n, vhost_iommu_unmap_notify,
>                          IOMMU_NOTIFIER_UNMAP,
>                          section->offset_within_region,
> -                        int128_get64(end));
> +                        int128_get64(end),
> +                        iommu_idx);
>      iommu->mr = section->mr;
>      iommu->iommu_offset = section->offset_within_address_space -
>                            section->offset_within_region;
> diff --git a/memory.c b/memory.c
> index 07d5fa7862..accb28d694 100644
> --- a/memory.c
> +++ b/memory.c
> @@ -1802,6 +1802,9 @@ void memory_region_register_iommu_notifier(MemoryRegion *mr,
>      iommu_mr = IOMMU_MEMORY_REGION(mr);
>      assert(n->notifier_flags != IOMMU_NOTIFIER_NONE);
>      assert(n->start <= n->end);
> +    assert(n->iommu_idx >= 0 &&
> +           n->iommu_idx < memory_region_iommu_num_indexes(iommu_mr));
> +
>      QLIST_INSERT_HEAD(&iommu_mr->iommu_notify, n, node);
>      memory_region_update_iommu_notify_flags(iommu_mr);
>  }
> @@ -1894,6 +1897,7 @@ void memory_region_notify_one(IOMMUNotifier *notifier,
>  }
>  
>  void memory_region_notify_iommu(IOMMUMemoryRegion *iommu_mr,
> +                                int iommu_idx,
>                                  IOMMUTLBEntry entry)
>  {
>      IOMMUNotifier *iommu_notifier;
> @@ -1901,7 +1905,9 @@ void memory_region_notify_iommu(IOMMUMemoryRegion *iommu_mr,
>      assert(memory_region_is_iommu(MEMORY_REGION(iommu_mr)));
>  
>      IOMMU_NOTIFIER_FOREACH(iommu_notifier, iommu_mr) {
> -        memory_region_notify_one(iommu_notifier, &entry);
> +        if (iommu_notifier->iommu_idx == iommu_idx) {
> +            memory_region_notify_one(iommu_notifier, &entry);
> +        }
>      }
>  }
>  
> 

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 15/27] iommu: Add IOMMU index argument to notifier APIs
  2018-05-24 15:29   ` Auger Eric
@ 2018-05-24 17:03     ` Peter Maydell
  2018-05-24 19:13       ` Auger Eric
  0 siblings, 1 reply; 114+ messages in thread
From: Peter Maydell @ 2018-05-24 17:03 UTC (permalink / raw)
  To: Auger Eric
  Cc: qemu-arm, QEMU Developers, Paolo Bonzini, Richard Henderson,
	Alex Bennée, patches

On 24 May 2018 at 16:29, Auger Eric <eric.auger@redhat.com> wrote:
> On 05/21/2018 04:03 PM, Peter Maydell wrote:
>> diff --git a/include/exec/memory.h b/include/exec/memory.h
>> index f6226fb263..4e6b125add 100644
>> --- a/include/exec/memory.h
>> +++ b/include/exec/memory.h
>> @@ -71,6 +71,7 @@ struct IOMMUTLBEntry {
>>      hwaddr           iova;
>>      hwaddr           translated_addr;
>>      hwaddr           addr_mask;  /* 0xfff = 4k translation */
>> +    int              iommu_idx;
> I don't get why ne need iommu_idx field here. On translate the caller
> has it. On notify the notifier has it?

I think this is an accidental leftover from some earlier draft;
nothing in the patchset actually reads or writes this field, and
it should be deleted.

>>      IOMMUAccessFlags perm;
>>  };
>>

>> diff --git a/hw/vfio/common.c b/hw/vfio/common.c
>> index 8e57265edf..fb396cf00a 100644
>> --- a/hw/vfio/common.c
>> +++ b/hw/vfio/common.c
>> @@ -507,6 +507,7 @@ static void vfio_listener_region_add(MemoryListener *listener,
>>      if (memory_region_is_iommu(section->mr)) {
>>          VFIOGuestIOMMU *giommu;
>>          IOMMUMemoryRegion *iommu_mr = IOMMU_MEMORY_REGION(section->mr);
>> +        int iommu_idx;
>>
>>          trace_vfio_listener_region_add_iommu(iova, end);
>>          /*
>> @@ -523,10 +524,13 @@ static void vfio_listener_region_add(MemoryListener *listener,
>>          llend = int128_add(int128_make64(section->offset_within_region),
>>                             section->size);
>>          llend = int128_sub(llend, int128_one());
>> +        iommu_idx = memory_region_iommu_attrs_to_index(iommu_mr,
>> +                                                       MEMTXATTRS_UNSPECIFIED);
> In that case VFIO ideally wants to be notified for any guest update
> (whatever the page set) to reprogram the physical IOMMU corresponding
> entries and doesn't want to register a notifier per iommu_idx. Also it
> does not know which ones are supported. Is there a corresponding
> iommu_idx value? MEMTXATTRS_ANY?

If VFIO is actually dealing with an IOMMU that needs to handle
multiple possible transactions for different tx attributes, then
it needs to know about all of them, because how it programs
the physical IOMMU needs to be different for "map X to Y for
Secure transactions" versus "map X to Y for NonSecure" (say).
(This would require new kernel APIs, I assume.)

If, as is currently the case, the VFIO infrastructure assumes that
the IOMMU will always translate any transaction from a device
identically regardless of its transaction attributes, then it
should just use MEMTXATTRS_UNSPECIFIED, and trust that the
emulated IOMMU will translate those correctly. (There might be
scope for VFIO checking that the IOMMU really does, eg that
it is only using one iommu index?)

Basically, VFIO is shadowing the behaviour of the emulated
IOMMU to reflect it into the kernel; if the IOMMU it's shadowing
is complicated then VFIO is going to need to be similarly
complicated, and "merge updates for different page tables
down into one" is not going to be the right behaviour.

thanks
-- PMM

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 15/27] iommu: Add IOMMU index argument to notifier APIs
  2018-05-24 17:03     ` Peter Maydell
@ 2018-05-24 19:13       ` Auger Eric
  0 siblings, 0 replies; 114+ messages in thread
From: Auger Eric @ 2018-05-24 19:13 UTC (permalink / raw)
  To: Peter Maydell
  Cc: qemu-arm, QEMU Developers, Paolo Bonzini, Richard Henderson,
	Alex Bennée, patches

Hi Peter,
On 05/24/2018 07:03 PM, Peter Maydell wrote:
> On 24 May 2018 at 16:29, Auger Eric <eric.auger@redhat.com> wrote:
>> On 05/21/2018 04:03 PM, Peter Maydell wrote:
>>> diff --git a/include/exec/memory.h b/include/exec/memory.h
>>> index f6226fb263..4e6b125add 100644
>>> --- a/include/exec/memory.h
>>> +++ b/include/exec/memory.h
>>> @@ -71,6 +71,7 @@ struct IOMMUTLBEntry {
>>>      hwaddr           iova;
>>>      hwaddr           translated_addr;
>>>      hwaddr           addr_mask;  /* 0xfff = 4k translation */
>>> +    int              iommu_idx;
>> I don't get why ne need iommu_idx field here. On translate the caller
>> has it. On notify the notifier has it?
> 
> I think this is an accidental leftover from some earlier draft;
> nothing in the patchset actually reads or writes this field, and
> it should be deleted.
> 
>>>      IOMMUAccessFlags perm;
>>>  };
>>>
> 
>>> diff --git a/hw/vfio/common.c b/hw/vfio/common.c
>>> index 8e57265edf..fb396cf00a 100644
>>> --- a/hw/vfio/common.c
>>> +++ b/hw/vfio/common.c
>>> @@ -507,6 +507,7 @@ static void vfio_listener_region_add(MemoryListener *listener,
>>>      if (memory_region_is_iommu(section->mr)) {
>>>          VFIOGuestIOMMU *giommu;
>>>          IOMMUMemoryRegion *iommu_mr = IOMMU_MEMORY_REGION(section->mr);
>>> +        int iommu_idx;
>>>
>>>          trace_vfio_listener_region_add_iommu(iova, end);
>>>          /*
>>> @@ -523,10 +524,13 @@ static void vfio_listener_region_add(MemoryListener *listener,
>>>          llend = int128_add(int128_make64(section->offset_within_region),
>>>                             section->size);
>>>          llend = int128_sub(llend, int128_one());
>>> +        iommu_idx = memory_region_iommu_attrs_to_index(iommu_mr,
>>> +                                                       MEMTXATTRS_UNSPECIFIED);
>> In that case VFIO ideally wants to be notified for any guest update
>> (whatever the page set) to reprogram the physical IOMMU corresponding
>> entries and doesn't want to register a notifier per iommu_idx. Also it
>> does not know which ones are supported. Is there a corresponding
>> iommu_idx value? MEMTXATTRS_ANY?
> 
> If VFIO is actually dealing with an IOMMU that needs to handle
> multiple possible transactions for different tx attributes, then
> it needs to know about all of them, because how it programs
> the physical IOMMU needs to be different for "map X to Y for
> Secure transactions" versus "map X to Y for NonSecure" (say).
> (This would require new kernel APIs, I assume.)

Hum agreed. In any case the iommu_idx must be passed to VFIO along with
the notification, either as part of the notifier itself or in the
IOMMUTLBEntry. So VFIO may need to enumerate the supported iommu_idx and
register a notifier for relevant ones.

Thanks

Eric
> 
> If, as is currently the case, the VFIO infrastructure assumes that
> the IOMMU will always translate any transaction from a device
> identically regardless of its transaction attributes, then it
> should just use MEMTXATTRS_UNSPECIFIED, and trust that the
> emulated IOMMU will translate those correctly. (There might be
> scope for VFIO checking that the IOMMU really does, eg that
> it is only using one iommu index?)
> 
> Basically, VFIO is shadowing the behaviour of the emulated
> IOMMU to reflect it into the kernel; if the IOMMU it's shadowing
> is complicated then VFIO is going to need to be similarly
> complicated, and "merge updates for different page tables
> down into one" is not going to be the right behaviour.
> 
> thanks
> -- PMM
> 

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 17/27] exec.c: Handle IOMMUs in address_space_translate_for_iotlb()
  2018-05-23  9:51   ` Alex Bennée
  2018-05-23 11:52     ` Peter Maydell
@ 2018-05-24 19:54     ` Auger Eric
  2018-05-25  8:52       ` Peter Maydell
  1 sibling, 1 reply; 114+ messages in thread
From: Auger Eric @ 2018-05-24 19:54 UTC (permalink / raw)
  To: Alex Bennée, Peter Maydell
  Cc: Paolo Bonzini, Richard Henderson, qemu-arm, qemu-devel, patches

Hi Peter,

On 05/23/2018 11:51 AM, Alex Bennée wrote:
> 
> Peter Maydell <peter.maydell@linaro.org> writes:
> 
>> Currently we don't support board configurations that put an IOMMU
>> in the path of the CPU's memory transactions, and instead just
>> assert() if the memory region fonud in address_space_translate_for_iotlb()
found
>> is an IOMMUMemoryRegion.
>>
>> Remove this limitation by having the function handle IOMMUs.
>> This is mostly straightforward, but we must make sure we have
>> a notifier registered for every IOMMU that a transaction has
>> passed through, so that we can flush the TLB appropriately
Can you elaborate on what (TCG) TLB we are talking about?

The concept of IOMMUs downstream to a CPU is not obvious to me. Maybe an
example may be documented in the commit message?
>> when any of the IOMMUs change their mappings.
>>
>> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
>> ---
>>  include/exec/exec-all.h |   3 +-
>>  include/qom/cpu.h       |   3 +
>>  accel/tcg/cputlb.c      |   3 +-
>>  exec.c                  | 147 +++++++++++++++++++++++++++++++++++++++-
>>  4 files changed, 152 insertions(+), 4 deletions(-)
>>
>> diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
>> index 4d09eaba72..e0ff19b711 100644
>> --- a/include/exec/exec-all.h
>> +++ b/include/exec/exec-all.h
>> @@ -469,7 +469,8 @@ void tb_flush_jmp_cache(CPUState *cpu, target_ulong addr);
>>
>>  MemoryRegionSection *
>>  address_space_translate_for_iotlb(CPUState *cpu, int asidx, hwaddr addr,
>> -                                  hwaddr *xlat, hwaddr *plen);
>> +                                  hwaddr *xlat, hwaddr *plen,
>> +                                  MemTxAttrs attrs, int *prot);
>>  hwaddr memory_region_section_get_iotlb(CPUState *cpu,
>>                                         MemoryRegionSection *section,
>>                                         target_ulong vaddr,
>> diff --git a/include/qom/cpu.h b/include/qom/cpu.h
>> index 9d3afc6c75..d4a30149dd 100644
>> --- a/include/qom/cpu.h
>> +++ b/include/qom/cpu.h
>> @@ -429,6 +429,9 @@ struct CPUState {
>>      uint16_t pending_tlb_flush;
>>
>>      int hvf_fd;
>> +
>> +    /* track IOMMUs whose translations we've cached in the TCG TLB */
>> +    GSList *iommu_notifiers;
> 
> So we are only concerned about TCG IOMMU notifiers here, specifically
> TCGIOMMUNotifier structures. Why not just use a GArray and save
> ourselves chasing pointers?
> 
>>  };
>>
>>  QTAILQ_HEAD(CPUTailQ, CPUState);
>> diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c
>> index 05439039e9..c8acaf21e9 100644
>> --- a/accel/tcg/cputlb.c
>> +++ b/accel/tcg/cputlb.c
>> @@ -632,7 +632,8 @@ void tlb_set_page_with_attrs(CPUState *cpu, target_ulong vaddr,
>>      }
>>
>>      sz = size;
>> -    section = address_space_translate_for_iotlb(cpu, asidx, paddr, &xlat, &sz);
>> +    section = address_space_translate_for_iotlb(cpu, asidx, paddr, &xlat, &sz,
>> +                                                attrs, &prot);
>>      assert(sz >= TARGET_PAGE_SIZE);
>>
>>      tlb_debug("vaddr=" TARGET_FMT_lx " paddr=0x" TARGET_FMT_plx
>> diff --git a/exec.c b/exec.c
>> index c9285c9c39..6c8f2dcc3f 100644
>> --- a/exec.c
>> +++ b/exec.c
>> @@ -650,18 +650,158 @@ MemoryRegion *flatview_translate(FlatView *fv, hwaddr addr, hwaddr *xlat,
>>      return mr;
>>  }
>>
>> +typedef struct TCGIOMMUNotifier {
>> +    IOMMUNotifier n;
>> +    MemoryRegion *mr;
>> +    CPUState *cpu;
> 
> This seems superfluous if we are storing the list of notifiers in the CPUState
> 
>> +    int iommu_idx;
>> +    bool active;
>> +} TCGIOMMUNotifier;
>> +
>> +static void tcg_iommu_unmap_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb)
>> +{
>> +    TCGIOMMUNotifier *notifier = container_of(n, TCGIOMMUNotifier, n);
>> +
>> +    if (!notifier->active) {
>> +        return;
>> +    }
>> +    tlb_flush(notifier->cpu);
>> +    notifier->active = false;
>> +    /* We leave the notifier struct on the list to avoid reallocating it later.
>> +     * Generally the number of IOMMUs a CPU deals with will be small.
>> +     * In any case we can't unregister the iommu notifier from a notify
>> +     * callback.
>> +     */
I don't get the life cycle of the notifier and why it becomes inactive
after the invalidate. Could you detail the specificity of this one?
>> +}
>> +
>> +static gint tcg_iommu_find_notifier(gconstpointer a, gconstpointer b)
>> +{
>> +    TCGIOMMUNotifier *notifier = (TCGIOMMUNotifier *)a;
>> +    TCGIOMMUNotifier *seeking = (TCGIOMMUNotifier *)b;
>> +
>> +    if (notifier->mr == seeking->mr &&
>> +        notifier->iommu_idx == seeking->iommu_idx) {
>> +        return 0;
>> +    }
>> +    return 1;
>> +}
>> +
>> +static void tcg_register_iommu_notifier(CPUState *cpu,
>> +                                        IOMMUMemoryRegion *iommu_mr,
>> +                                        int iommu_idx)
>> +{
>> +    /* Make sure this CPU has an IOMMU notifier registered for this
>> +     * IOMMU/IOMMU index combination, so that we can flush its TLB
>> +     * when the IOMMU tells us the mappings we've cached have changed.
>> +     */
>> +    TCGIOMMUNotifier seeking = {
>> +        .mr = MEMORY_REGION(iommu_mr),
>> +        .iommu_idx = iommu_idx,
>> +    };
>> +    TCGIOMMUNotifier *notifier;
>> +    GSList *found = g_slist_find_custom(cpu->iommu_notifiers,
>> +                                        &seeking,
>> +                                        tcg_iommu_find_notifier);
>> +    if (found) {
>> +        notifier = found->data;
>> +    } else {
>> +        notifier = g_new0(TCGIOMMUNotifier, 1);
>> +        notifier->mr = seeking.mr;
>> +        notifier->iommu_idx = iommu_idx;
>> +        notifier->cpu = cpu;
>> +        /* Rather than trying to register interest in the specific part
>> +         * of the iommu's address space that we've accessed and then
>> +         * expand it later as subsequent accesses touch more of it, we
>> +         * just register interest in the whole thing, on the assumption
>> +         * that iommu reconfiguration will be rare.
>> +         */
>> +        iommu_notifier_init(&notifier->n,
>> +                            tcg_iommu_unmap_notify,
>> +                            IOMMU_NOTIFIER_UNMAP,
>> +                            0,
>> +                            HWADDR_MAX,
>> +                            iommu_idx);
>> +        memory_region_register_iommu_notifier(notifier->mr, &notifier->n);
>> +        cpu->iommu_notifiers = g_slist_prepend(cpu->iommu_notifiers,
>> +                                               notifier);
>> +    }
>> +    if (!notifier->active) {
>> +        notifier->active = true;
>> +    }
>> +}
>> +
>> +static void tcg_iommu_notifier_destroy(gpointer data)
>> +{
>> +    TCGIOMMUNotifier *notifier = data;
>> +
>> +    if (notifier->active) {
>> +        memory_region_unregister_iommu_notifier(notifier->mr, &notifier->n);
>> +    }
Is it safe to leave the notifier registered to an IOMMU whereas it gets
freed?

Thanks

Eric
>> +    g_free(notifier);
>> +}
>> +
>> +static void tcg_iommu_free_notifier_list(CPUState *cpu)
>> +{
>> +    /* Destroy the CPU's notifier list */
>> +    g_slist_free_full(cpu->iommu_notifiers, tcg_iommu_notifier_destroy);
>> +    cpu->iommu_notifiers = NULL;
>> +}
>> +
>>  /* Called from RCU critical section */
>>  MemoryRegionSection *
>>  address_space_translate_for_iotlb(CPUState *cpu, int asidx, hwaddr addr,
>> -                                  hwaddr *xlat, hwaddr *plen)
>> +                                  hwaddr *xlat, hwaddr *plen,
>> +                                  MemTxAttrs attrs, int *prot)
>>  {
>>      MemoryRegionSection *section;
>> +    IOMMUMemoryRegion *iommu_mr;
>> +    IOMMUMemoryRegionClass *imrc;
>> +    IOMMUTLBEntry iotlb;
>> +    int iommu_idx;
>>      AddressSpaceDispatch *d = atomic_rcu_read(&cpu->cpu_ases[asidx].memory_dispatch);
>>
>> -    section = address_space_translate_internal(d, addr, xlat, plen, false);
>> +    for (;;) {
>> +        section = address_space_translate_internal(d, addr, &addr, plen, false);
>> +
>> +        iommu_mr = memory_region_get_iommu(section->mr);
>> +        if (!iommu_mr) {
>> +            break;
>> +        }
>> +
>> +        imrc = memory_region_get_iommu_class_nocheck(iommu_mr);
>> +
>> +        iommu_idx = imrc->attrs_to_index(iommu_mr, attrs);
>> +        tcg_register_iommu_notifier(cpu, iommu_mr, iommu_idx);
>> +        /* We need all the permissions, so pass IOMMU_NONE so the IOMMU
>> +         * doesn't short-cut its translation table walk.
it is not clear to me why you don't use the access flag as you seem to
handle the perm fault after the translate() call.

Thanks

Eric
>> +         */
>> +        iotlb = imrc->translate(iommu_mr, addr, IOMMU_NONE, iommu_idx);
>> +        addr = ((iotlb.translated_addr & ~iotlb.addr_mask)
>> +                | (addr & iotlb.addr_mask));
>> +        /* Update the caller's prot bits to remove permissions the IOMMU
>> +         * is giving us a failure response for. If we get down to no
>> +         * permissions left at all we can give up now.
>> +         */
>> +        if (!(iotlb.perm & IOMMU_RO)) {
>> +            *prot &= ~(PAGE_READ | PAGE_EXEC);
>> +        }
>> +        if (!(iotlb.perm & IOMMU_WO)) {
>> +            *prot &= ~PAGE_WRITE;
>> +        }
>> +
>> +        if (!*prot) {
>> +            goto translate_fail;
>> +        }
>> +
>> +        d = flatview_to_dispatch(address_space_to_flatview(iotlb.target_as));
>> +    }
>>
>>      assert(!memory_region_is_iommu(section->mr));
>> +    *xlat = addr;
>>      return section;
>> +
>> +translate_fail:
>> +    return &d->map.sections[PHYS_SECTION_UNASSIGNED];
>>  }
>>  #endif
>>
>> @@ -820,6 +960,9 @@ void cpu_exec_unrealizefn(CPUState *cpu)
>>      if (qdev_get_vmsd(DEVICE(cpu)) == NULL) {
>>          vmstate_unregister(NULL, &vmstate_cpu_common, cpu);
>>      }
>> +#ifndef CONFIG_USER_ONLY
>> +    tcg_iommu_free_notifier_list(cpu);
>> +#endif
>>  }
>>
>>  Property cpu_common_props[] = {
> 
> 
> --
> Alex Bennée
> 

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 14/27] iommu: Add IOMMU index concept to IOMMU API
  2018-05-24 10:54                 ` Peter Maydell
@ 2018-05-25  2:50                   ` Peter Xu
  2018-05-25  9:27                   ` Auger Eric
  1 sibling, 0 replies; 114+ messages in thread
From: Peter Xu @ 2018-05-25  2:50 UTC (permalink / raw)
  To: Peter Maydell
  Cc: qemu-arm, QEMU Developers, Paolo Bonzini, Richard Henderson,
	Alex Bennée, patches, David Gibson, Alex Williamson

On Thu, May 24, 2018 at 11:54:17AM +0100, Peter Maydell wrote:
> On 24 May 2018 at 07:23, Peter Xu <peterx@redhat.com> wrote:
> > On Wed, May 23, 2018 at 12:47:16PM +0100, Peter Maydell wrote:
> >> On 23 May 2018 at 02:06, Peter Xu <peterx@redhat.com> wrote:
> >> > Could you elaborate a bit more on why IOMMU notifier failed to
> >> > corporate when passing in MemTxAttrs?  I am not sure I caught the idea
> >> > here, but can we copy the MemTxAttrs into IOMMUTLBEntry when
> >> > translating, then in IOMMU notifiers we can know the attrs (if that is
> >> > what MPC wants)?
> >>
> >> (1) The notifier API lets you register a notifier before you've
> >> called the translate API
> >
> > Yes.
> >
> >> (2) An IOMMUTLBEntry can be valid for more than just the txattrs
> >> that it was passed in (for instance, if an IOMMU doesn't care
> >> about txattrs at all, then the resulting TLB entry is valid for
> >> any txattrs; or if the IOMMU only cares about attrs.secure the
> >> resulting TLB entries are valid for both attrs.user=0 and
> >> attrs.user=1).
> >
> > [1]
> >
> > Yes exactly, that's why I thought copying the txattrs into IOTLB
> > should work.
> 
> I'm a bit confused about why the IOMMUTLBEntry is relevant here.
> That's the thing returned from the translate method, so there's
> no point in copying txattrs into it, because the caller by definition
> already had them. At the point where the IOMMU notices a guest
> changed the config, it doesn't have an IOMMUTLBEntry or a set of
> tx attrs.

Yes the txattrs is not for the translate() callers, but for IOMMU
notifiers only.  Thanks for the pointer below [1], I think it's very
similar to what Paolo mentioned there at [1], the major difference is
that Paolo suggested to put txattrs into both IOMMUNotify and
memory_region_notify_one(), while my above suggestion is that we can
directly copy it into IOMMUTLBEntry - note that both IOMMUNotify and
memory_region_notify_one will have a IOMMUTLBEntry parameter.  Though
I am not 100% clear on Paolo's suggestion on why to add two txattrs
parameters for each function (since I thought all the values in
txattrs to be passed to either IOMMUNotify or memory_region_notify_one
should be valid, so I am not sure why we need to "indicate which
attributes matter (0 = indifferent, 1 = matter)").

> 
> >> (3) when the IOMMU calls the notifier because the guest config
> >> changed it doesn't have tx attributes, so it would have to
> >> fabricate some; and the guest config will invalidate transactions
> >> with some combinations of tx attributes and not others.
> >
> > IMHO it doesn't directly matter with what we are discussing now.  That
> > IOMMU_NOTIFIER_[UN]MAP flag tells what kind of message would the
> > notifier be interested in from "what kind of mapping it is".  IMHO
> > it's not really related to some other attributes when translation
> > happens - in our case, it does not directly related to what txattrs
> > value is.  Here as mentioned at [1] above IMHO we can still check this
> > against txattrs in the notifier handler, then we ignore messages that
> > we don't care about.  Actually the IOMMU_NOTIFIER_[UN]MAP flags can be
> > removed and we can just do similar things (e.g., we can skip MAP
> > messages if we only care about UNMAP messages), but since it's a
> > general concept and easy to be generalized, so we provided these
> > MAP/UNMAP flags to ease the notifier hooks.
> >
> > In other words, I think we can also add more flags for SECURE or not.
> > However I still don't see a reason (from above three points) on why we
> > can't pass in txattrs directly into translate(), and at the same time
> > we copy the txattrs into IOTLB so that IOMMUTLBEntry can contain some
> > context information. [2]
> 
> I'm afraid I really don't understand the design you're proposing
> here. But overall I think the point of divergence is that
> the mapping from "transaction attributes" to "translation contexts"
> (ie, effectively different page tables) is not 1:1. So for instance:
> 
> Our current IOMMUs which don't care about txattrs:
> 
>   [any txattr at all] -> the one and only translation context
> 
> An IOMMU which cares about attrs.secure, and also treats
> attrs.unspecified like secure:
>   [any txattr with attrs.secure = 1]  \-> 'secure' context'
>   MEMATTRS_UNSPECIFIED                /
> 
>   [txattrs with secure = 1] -> 'nonsecure' context

(This part is a bit interesting - the "secure" bit is actually flipped
 between txattrs and the context...)

> 
> An IOMMU which cares about attrs.secure and attrs.user:
>   [secure=1,user=1]   -> 'secure user' context
>   [secure=0,user=1]   -> 'ns user' context
>   [secure=1,user=0]   -> 's priv' context
>   [secure=0,user=0]   -> 'ns priv' context
> 
> The IOMMU index captures this idea that there is not a 1:1
> mapping, so we have a way to think about and refer to the
> actual set of translation contexts that the IOMMU has.

Yes.  I'd say I am not really against this iommu_idx idea.  My only
worry is that I'm not sure whether that'll be good enough for the
future usage of IOMMU, e.g., the requester ID issue to be discussed
and solved.  My understanding is that the txattrs is already a
superset of the iommu_idx concept.  Meanwhile, the iommu_idx concept
is not easy to understand.  So it'll be nice if we can solve the
problem with what we already have now (no new concept like iommu_idx),
easier to understand, meanwhile it even covers more possibilities in
the future (we can easily generate iommu_idx by txattrs, but not other
way round).

> 
> >> As Paolo pointed out you could also implement this by rather
> >> of having an iommu_index concept, instead having some kind
> >> of "here is a mask of which txattrs fields matter, and here's
> >> another parameter with which txattrs fields are affected".
> >> That makes it awkward though to implement "txattrs.unspecified
> >> acts like txattrs.secure == 1" type behaviour, though, which is
> >> easy with an index abstraction layer. It also would be harder
> >> to implement the default 'replay' method, I think.
> >
> > Please refer to my above comment at [2] - I am still confused on why
> > we must use this iommu_idx concept.  How about we just introduce
> > IOMMU_NOTIFIER_SECURE (or something similar) and let TCG code register
> > with that?  Though for the rest of notifiers we'll need to touch up
> > too to make sure all existing notifiers will still receive all the
> > message, no matter whether it's secure or not.
> 
> I think I would definitely prefer not to have the secure/nonsecure
> specific thing in the API. We've got good experience with TCG
> where we abstract away the specifics of what an MMU cares about
> into an mmu_index, and I'd like to keep that approach. Otherwise,
> you immediately get into "and now we need to change the API again
> to handle IOMMUs which care about attrs.user"; and then again
> for attrs.requester_id; and now what about IOMMUs that care
> about both secure and user... Better to have an abstraction so
> that we don't need to keep changing the core code. In particular,
> TCG doesn't know whether it's secure/nonsecure that matters -- that
> is mostly handled by the target-specific parts, and TCG core code
> just passes attributes around.

IMHO the notifier flags are of course extra - we can introduce new
flags, or we can just handle them in the notifier hooks without
touching that part (especially if we copy the txattrs into
IOMMUTLBEntry we don't even need to touch the notifier API).  IMHO the
thing that matters more is what we need to pass to the translate() and
whether the iommu_idx concept is a must.  I am really fine with either
way to implement the IOMMU notifiers when we can make sure whether
iommu_idx is a must.

Again, I am totally not against the iommu_idx concept - I am just
afraid one day that'll be not enough for us and we still need to
rework on that part.

> 
> > I'd also appreciate if you could paste me the link for Paolo's
> > message, since I cannot find it.
> 
> This is the one I had in mind:
> https://lists.gnu.org/archive/html/qemu-devel/2018-05/msg03522.html

[1]

Really sorry to chime in so late no matter what; I didn't noticed the
RFC series.  These comments are for sure more suitable for RFCs.

> 
> >> It will only need to do so for IOMMUs that care about that field.
> >>
> >> (See also the other thread with Eric Auger talking about
> >> maybe caring about requester_id like that. Needing to look
> >> at requester_id is an area I haven't thought too much about,
> >> and it is a bit of an odd one because it's a much larger
> >> space than any of the other parts of the txattrs. In some
> >> cases it ought to be possible to say "requester_id lets
> >> us determine an iommu index, and there are a lot fewer
> >> than 2^16 actual iommu indexes because a lot of the requestor_id
> >> values indicate the same actual iommu translation", I suspect.)
> >
> > AFAIK requester_id will only be the same in very rare cases, for
> > example, when multiple PCI devices (no matter whether it's PCI or
> > PCIe) are under the same PCIe-to-PCI bridge, then all these devices
> > will use the bridge's requester ID as their own.  In most cases, each
> > PCIe device will have their own unique requester ID.  So it'll be
> > common that requester ID number can be at least equal to the number of
> > devices.
> 
> I haven't looked at this, but my understanding is that at the moment
> we do per-device requester_id by having each PCI device get its own
> IOMMUMemoryRegion mapped into its address space. So we'd only need
> to look at requester_id for the case of devices with multiple
> subfunctions(?), and presumably most devices only have a handful
> of those.

Not sure I fully understand this, do you mean that requester ID can
actually be bound to the DMA address space (and the IOMMU memory
regions) for the device?  I am not sure, maybe yes...

Though ppassing txattrs (and requester ID) from the translate()
function still seems more reasonable. I assume that looks more like
what the real hardware does - the requester ID should be embeded in
the PCIe packet when sending the DMA request (or page translation
request).  And for me the translate() emulates the page translation
requests, that's why passing in txattrs is very easy to understand at
least for me (while the iommu_idx is not easy to understand;
especially the "index" let me think about "which IOMMU is responsible
for this").

Thanks,

-- 
Peter Xu

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 17/27] exec.c: Handle IOMMUs in address_space_translate_for_iotlb()
  2018-05-24 19:54     ` Auger Eric
@ 2018-05-25  8:52       ` Peter Maydell
  2018-05-25  9:50         ` Auger Eric
  0 siblings, 1 reply; 114+ messages in thread
From: Peter Maydell @ 2018-05-25  8:52 UTC (permalink / raw)
  To: Auger Eric
  Cc: Alex Bennée, Paolo Bonzini, Richard Henderson, qemu-arm,
	QEMU Developers, patches

On 24 May 2018 at 20:54, Auger Eric <eric.auger@redhat.com> wrote:
> Hi Peter,
>
> On 05/23/2018 11:51 AM, Alex Bennée wrote:
>>
>> Peter Maydell <peter.maydell@linaro.org> writes:
>>
>>> Currently we don't support board configurations that put an IOMMU
>>> in the path of the CPU's memory transactions, and instead just
>>> assert() if the memory region fonud in address_space_translate_for_iotlb()
> found
>>> is an IOMMUMemoryRegion.
>>>
>>> Remove this limitation by having the function handle IOMMUs.
>>> This is mostly straightforward, but we must make sure we have
>>> a notifier registered for every IOMMU that a transaction has
>>> passed through, so that we can flush the TLB appropriately
> Can you elaborate on what (TCG) TLB we are talking about?

The TCG TLB, as implemented in accel/tcg/cputlb.c. Basically
the thing that caches the results it gets back from the memory
system so it can fast path device and memory accesses.

> The concept of IOMMUs downstream to a CPU is not obvious to me. Maybe an
> example may be documented in the commit message?

The MPC implemented in this patchset is an example.



>>> +static void tcg_iommu_unmap_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb)
>>> +{
>>> +    TCGIOMMUNotifier *notifier = container_of(n, TCGIOMMUNotifier, n);
>>> +
>>> +    if (!notifier->active) {
>>> +        return;
>>> +    }
>>> +    tlb_flush(notifier->cpu);
>>> +    notifier->active = false;
>>> +    /* We leave the notifier struct on the list to avoid reallocating it later.
>>> +     * Generally the number of IOMMUs a CPU deals with will be small.
>>> +     * In any case we can't unregister the iommu notifier from a notify
>>> +     * callback.
>>> +     */
> I don't get the life cycle of the notifier and why it becomes inactive
> after the invalidate. Could you detail the specificity of this one?

Once we've flushed the TLB it is empty and will have no cached
information from the IOMMU. So there's no point in flushing the
TLB again (which is expensive) until the next time a transaction
goes through the IOMMU and we're caching something from it.

So the cycle goes:
 * CPU makes transaction that goes through an IOMMU
 * in tcg_register_iommu_notifier() we register the notifier
   if we haven't already, and make sure it's got active = true
 * in the unmap notify, we flush the whole TLB for the CPU, and
   set active = false
 * repeat...


>>> +static void tcg_iommu_notifier_destroy(gpointer data)
>>> +{
>>> +    TCGIOMMUNotifier *notifier = data;
>>> +
>>> +    if (notifier->active) {
>>> +        memory_region_unregister_iommu_notifier(notifier->mr, &notifier->n);
>>> +    }
> Is it safe to leave the notifier registered to an IOMMU whereas it gets
> freed?

Oh, this is a bug, left over from my first idea (which was to
unregister the IOMMU notifier in the notifier unmap callback,
in which case active == true would be the only case when we
had a registered notifier).

We should unconditionally unregister the notifier here.


>>>  /* Called from RCU critical section */
>>>  MemoryRegionSection *
>>>  address_space_translate_for_iotlb(CPUState *cpu, int asidx, hwaddr addr,
>>> -                                  hwaddr *xlat, hwaddr *plen)
>>> +                                  hwaddr *xlat, hwaddr *plen,
>>> +                                  MemTxAttrs attrs, int *prot)
>>>  {
>>>      MemoryRegionSection *section;
>>> +    IOMMUMemoryRegion *iommu_mr;
>>> +    IOMMUMemoryRegionClass *imrc;
>>> +    IOMMUTLBEntry iotlb;
>>> +    int iommu_idx;
>>>      AddressSpaceDispatch *d = atomic_rcu_read(&cpu->cpu_ases[asidx].memory_dispatch);
>>>
>>> -    section = address_space_translate_internal(d, addr, xlat, plen, false);
>>> +    for (;;) {
>>> +        section = address_space_translate_internal(d, addr, &addr, plen, false);
>>> +
>>> +        iommu_mr = memory_region_get_iommu(section->mr);
>>> +        if (!iommu_mr) {
>>> +            break;
>>> +        }
>>> +
>>> +        imrc = memory_region_get_iommu_class_nocheck(iommu_mr);
>>> +
>>> +        iommu_idx = imrc->attrs_to_index(iommu_mr, attrs);
>>> +        tcg_register_iommu_notifier(cpu, iommu_mr, iommu_idx);
>>> +        /* We need all the permissions, so pass IOMMU_NONE so the IOMMU
>>> +         * doesn't short-cut its translation table walk.
> it is not clear to me why you don't use the access flag as you seem to
> handle the perm fault after the translate() call.

We need to know all the permissions (because we'll cache the result
in the TCG TLB and later use them for future read and write accesses),
so we pass IOMMU_NONE.

My understanding from previous discussion is that the only
reason to pass in some other access flag value is if you
only care about one of read or write and want to allow the
IOMMU to stop walking the page table early as soon as it decides
it doesn't have permissions.

thanks
-- PMM

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 14/27] iommu: Add IOMMU index concept to IOMMU API
  2018-05-24 10:54                 ` Peter Maydell
  2018-05-25  2:50                   ` Peter Xu
@ 2018-05-25  9:27                   ` Auger Eric
  2018-05-25  9:34                     ` Peter Maydell
  1 sibling, 1 reply; 114+ messages in thread
From: Auger Eric @ 2018-05-25  9:27 UTC (permalink / raw)
  To: Peter Maydell, Peter Xu
  Cc: patches, QEMU Developers, Alex Williamson, qemu-arm,
	Paolo Bonzini, David Gibson, Alex Bennée, Richard Henderson

Hi Peter,

On 05/24/2018 12:54 PM, Peter Maydell wrote:
> On 24 May 2018 at 07:23, Peter Xu <peterx@redhat.com> wrote:
>> On Wed, May 23, 2018 at 12:47:16PM +0100, Peter Maydell wrote:
>>> On 23 May 2018 at 02:06, Peter Xu <peterx@redhat.com> wrote:
>>>> Could you elaborate a bit more on why IOMMU notifier failed to
>>>> corporate when passing in MemTxAttrs?  I am not sure I caught the idea
>>>> here, but can we copy the MemTxAttrs into IOMMUTLBEntry when
>>>> translating, then in IOMMU notifiers we can know the attrs (if that is
>>>> what MPC wants)?
>>>
>>> (1) The notifier API lets you register a notifier before you've
>>> called the translate API
>>
>> Yes.
>>
>>> (2) An IOMMUTLBEntry can be valid for more than just the txattrs
>>> that it was passed in (for instance, if an IOMMU doesn't care
>>> about txattrs at all, then the resulting TLB entry is valid for
>>> any txattrs; or if the IOMMU only cares about attrs.secure the
>>> resulting TLB entries are valid for both attrs.user=0 and
>>> attrs.user=1).
>>
>> [1]
>>
>> Yes exactly, that's why I thought copying the txattrs into IOTLB
>> should work.
> 
> I'm a bit confused about why the IOMMUTLBEntry is relevant here.
> That's the thing returned from the translate method, so there's
> no point in copying txattrs into it, because the caller by definition
> already had them. At the point where the IOMMU notices a guest
> changed the config, it doesn't have an IOMMUTLBEntry or a set of
> tx attrs.
> 
>>> (3) when the IOMMU calls the notifier because the guest config
>>> changed it doesn't have tx attributes, so it would have to
>>> fabricate some; and the guest config will invalidate transactions
>>> with some combinations of tx attributes and not others.
>>
>> IMHO it doesn't directly matter with what we are discussing now.  That
>> IOMMU_NOTIFIER_[UN]MAP flag tells what kind of message would the
>> notifier be interested in from "what kind of mapping it is".  IMHO
>> it's not really related to some other attributes when translation
>> happens - in our case, it does not directly related to what txattrs
>> value is.  Here as mentioned at [1] above IMHO we can still check this
>> against txattrs in the notifier handler, then we ignore messages that
>> we don't care about.  Actually the IOMMU_NOTIFIER_[UN]MAP flags can be
>> removed and we can just do similar things (e.g., we can skip MAP
>> messages if we only care about UNMAP messages), but since it's a
>> general concept and easy to be generalized, so we provided these
>> MAP/UNMAP flags to ease the notifier hooks.
>>
>> In other words, I think we can also add more flags for SECURE or not.
>> However I still don't see a reason (from above three points) on why we
>> can't pass in txattrs directly into translate(), and at the same time
>> we copy the txattrs into IOTLB so that IOMMUTLBEntry can contain some
>> context information. [2]
> 
> I'm afraid I really don't understand the design you're proposing
> here. But overall I think the point of divergence is that
> the mapping from "transaction attributes" to "translation contexts"
> (ie, effectively different page tables) is not 1:1. So for instance:
> 
> Our current IOMMUs which don't care about txattrs:
> 
>   [any txattr at all] -> the one and only translation context
> 
> An IOMMU which cares about attrs.secure, and also treats
> attrs.unspecified like secure:
>   [any txattr with attrs.secure = 1]  \-> 'secure' context'
>   MEMATTRS_UNSPECIFIED                /
> 
>   [txattrs with secure = 1] -> 'nonsecure' context
> 
> An IOMMU which cares about attrs.secure and attrs.user:
>   [secure=1,user=1]   -> 'secure user' context
>   [secure=0,user=1]   -> 'ns user' context
>   [secure=1,user=0]   -> 's priv' context
>   [secure=0,user=0]   -> 'ns priv' context

I fail to understand the PRIV attribute usage in SMMUv3.
My understanding is the STRW (ie. stream world, kind of indication of
the exception level the SID is used along) in the STE is used to
determine the correct TTB*. Isn't PRIV checked against the page table
attributes only?

So would be expose 4 indexes for SMMUv3 or only 2 (S and NS)?

Thanks

Eric
> 
> The IOMMU index captures this idea that there is not a 1:1
> mapping, so we have a way to think about and refer to the
> actual set of translation contexts that the IOMMU has.
> 
>>> As Paolo pointed out you could also implement this by rather
>>> of having an iommu_index concept, instead having some kind
>>> of "here is a mask of which txattrs fields matter, and here's
>>> another parameter with which txattrs fields are affected".
>>> That makes it awkward though to implement "txattrs.unspecified
>>> acts like txattrs.secure == 1" type behaviour, though, which is
>>> easy with an index abstraction layer. It also would be harder
>>> to implement the default 'replay' method, I think.
>>
>> Please refer to my above comment at [2] - I am still confused on why
>> we must use this iommu_idx concept.  How about we just introduce
>> IOMMU_NOTIFIER_SECURE (or something similar) and let TCG code register
>> with that?  Though for the rest of notifiers we'll need to touch up
>> too to make sure all existing notifiers will still receive all the
>> message, no matter whether it's secure or not.
> 
> I think I would definitely prefer not to have the secure/nonsecure
> specific thing in the API. We've got good experience with TCG
> where we abstract away the specifics of what an MMU cares about
> into an mmu_index, and I'd like to keep that approach. Otherwise,
> you immediately get into "and now we need to change the API again
> to handle IOMMUs which care about attrs.user"; and then again
> for attrs.requester_id; and now what about IOMMUs that care
> about both secure and user... Better to have an abstraction so
> that we don't need to keep changing the core code. In particular,
> TCG doesn't know whether it's secure/nonsecure that matters -- that
> is mostly handled by the target-specific parts, and TCG core code
> just passes attributes around.
> 
>> I'd also appreciate if you could paste me the link for Paolo's
>> message, since I cannot find it.
> 
> This is the one I had in mind:
> https://lists.gnu.org/archive/html/qemu-devel/2018-05/msg03522.html
> 
>>> It will only need to do so for IOMMUs that care about that field.
>>>
>>> (See also the other thread with Eric Auger talking about
>>> maybe caring about requester_id like that. Needing to look
>>> at requester_id is an area I haven't thought too much about,
>>> and it is a bit of an odd one because it's a much larger
>>> space than any of the other parts of the txattrs. In some
>>> cases it ought to be possible to say "requester_id lets
>>> us determine an iommu index, and there are a lot fewer
>>> than 2^16 actual iommu indexes because a lot of the requestor_id
>>> values indicate the same actual iommu translation", I suspect.)
>>
>> AFAIK requester_id will only be the same in very rare cases, for
>> example, when multiple PCI devices (no matter whether it's PCI or
>> PCIe) are under the same PCIe-to-PCI bridge, then all these devices
>> will use the bridge's requester ID as their own.  In most cases, each
>> PCIe device will have their own unique requester ID.  So it'll be
>> common that requester ID number can be at least equal to the number of
>> devices.
> 
> I haven't looked at this, but my understanding is that at the moment
> we do per-device requester_id by having each PCI device get its own
> IOMMUMemoryRegion mapped into its address space. So we'd only need
> to look at requester_id for the case of devices with multiple
> subfunctions(?), and presumably most devices only have a handful
> of those.
> 
> thanks
> -- PMM
> 

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 14/27] iommu: Add IOMMU index concept to IOMMU API
  2018-05-25  9:27                   ` Auger Eric
@ 2018-05-25  9:34                     ` Peter Maydell
  0 siblings, 0 replies; 114+ messages in thread
From: Peter Maydell @ 2018-05-25  9:34 UTC (permalink / raw)
  To: Auger Eric
  Cc: Peter Xu, patches, QEMU Developers, Alex Williamson, qemu-arm,
	Paolo Bonzini, David Gibson, Alex Bennée, Richard Henderson

On 25 May 2018 at 10:27, Auger Eric <eric.auger@redhat.com> wrote:
> I fail to understand the PRIV attribute usage in SMMUv3.
> My understanding is the STRW (ie. stream world, kind of indication of
> the exception level the SID is used along) in the STE is used to
> determine the correct TTB*. Isn't PRIV checked against the page table
> attributes only?

I haven't looked too closely at the details for the SMMUv3.
But basically if you can return different results for
"transaction is priv" vs "transaction is user" then you need
separate iommu indexes, even if the only difference might
be in the permissions. (This is because an IOMMUTLBEntry
can only specify one set of r/w permissions; it can't
tell you the permissions separately for priv vs user.) If the
SMMUv3 always reports the same permissions and address regardless
of the transaction's priv attribute, then it doesn't need
to use separate indexes for them.

thanks
-- PMM

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 17/27] exec.c: Handle IOMMUs in address_space_translate_for_iotlb()
  2018-05-25  8:52       ` Peter Maydell
@ 2018-05-25  9:50         ` Auger Eric
  2018-05-25  9:59           ` Peter Maydell
  0 siblings, 1 reply; 114+ messages in thread
From: Auger Eric @ 2018-05-25  9:50 UTC (permalink / raw)
  To: Peter Maydell
  Cc: patches, QEMU Developers, qemu-arm, Paolo Bonzini,
	Alex Bennée, Richard Henderson

Hi Peter,

On 05/25/2018 10:52 AM, Peter Maydell wrote:
> On 24 May 2018 at 20:54, Auger Eric <eric.auger@redhat.com> wrote:
>> Hi Peter,
>>
>> On 05/23/2018 11:51 AM, Alex Bennée wrote:
>>>
>>> Peter Maydell <peter.maydell@linaro.org> writes:
>>>
>>>> Currently we don't support board configurations that put an IOMMU
>>>> in the path of the CPU's memory transactions, and instead just
>>>> assert() if the memory region fonud in address_space_translate_for_iotlb()
>> found
>>>> is an IOMMUMemoryRegion.
>>>>
>>>> Remove this limitation by having the function handle IOMMUs.
>>>> This is mostly straightforward, but we must make sure we have
>>>> a notifier registered for every IOMMU that a transaction has
>>>> passed through, so that we can flush the TLB appropriately
>> Can you elaborate on what (TCG) TLB we are talking about?
> 
> The TCG TLB, as implemented in accel/tcg/cputlb.c. Basically
> the thing that caches the results it gets back from the memory
> system so it can fast path device and memory accesses.
> 
>> The concept of IOMMUs downstream to a CPU is not obvious to me. Maybe an
>> example may be documented in the commit message?
> 
> The MPC implemented in this patchset is an example.
> 
> 
> 
>>>> +static void tcg_iommu_unmap_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb)
>>>> +{
>>>> +    TCGIOMMUNotifier *notifier = container_of(n, TCGIOMMUNotifier, n);
>>>> +
>>>> +    if (!notifier->active) {
>>>> +        return;
>>>> +    }
>>>> +    tlb_flush(notifier->cpu);
>>>> +    notifier->active = false;
>>>> +    /* We leave the notifier struct on the list to avoid reallocating it later.
>>>> +     * Generally the number of IOMMUs a CPU deals with will be small.
>>>> +     * In any case we can't unregister the iommu notifier from a notify
>>>> +     * callback.
>>>> +     */
>> I don't get the life cycle of the notifier and why it becomes inactive
>> after the invalidate. Could you detail the specificity of this one?
> 
> Once we've flushed the TLB it is empty and will have no cached
> information from the IOMMU. So there's no point in flushing the
> TLB again (which is expensive) until the next time a transaction
> goes through the IOMMU and we're caching something from it.
Ak OK. there is no finer granularity for TLB flush?

> 
> So the cycle goes:
>  * CPU makes transaction that goes through an IOMMU
>  * in tcg_register_iommu_notifier() we register the notifier
>    if we haven't already, and make sure it's got active = true
>  * in the unmap notify, we flush the whole TLB for the CPU, and
>    set active = false
>  * repeat...
OK thank you for the explanation
> 
> 
>>>> +static void tcg_iommu_notifier_destroy(gpointer data)
>>>> +{
>>>> +    TCGIOMMUNotifier *notifier = data;
>>>> +
>>>> +    if (notifier->active) {
>>>> +        memory_region_unregister_iommu_notifier(notifier->mr, &notifier->n);
>>>> +    }
>> Is it safe to leave the notifier registered to an IOMMU whereas it gets
>> freed?
> 
> Oh, this is a bug, left over from my first idea (which was to
> unregister the IOMMU notifier in the notifier unmap callback,
> in which case active == true would be the only case when we
> had a registered notifier).
> 
> We should unconditionally unregister the notifier here.
> 
> 
>>>>  /* Called from RCU critical section */
>>>>  MemoryRegionSection *
>>>>  address_space_translate_for_iotlb(CPUState *cpu, int asidx, hwaddr addr,
>>>> -                                  hwaddr *xlat, hwaddr *plen)
>>>> +                                  hwaddr *xlat, hwaddr *plen,
>>>> +                                  MemTxAttrs attrs, int *prot)
>>>>  {
>>>>      MemoryRegionSection *section;
>>>> +    IOMMUMemoryRegion *iommu_mr;
>>>> +    IOMMUMemoryRegionClass *imrc;
>>>> +    IOMMUTLBEntry iotlb;
>>>> +    int iommu_idx;
>>>>      AddressSpaceDispatch *d = atomic_rcu_read(&cpu->cpu_ases[asidx].memory_dispatch);
>>>>
>>>> -    section = address_space_translate_internal(d, addr, xlat, plen, false);
>>>> +    for (;;) {
>>>> +        section = address_space_translate_internal(d, addr, &addr, plen, false);
>>>> +
>>>> +        iommu_mr = memory_region_get_iommu(section->mr);
>>>> +        if (!iommu_mr) {
>>>> +            break;
>>>> +        }
>>>> +
>>>> +        imrc = memory_region_get_iommu_class_nocheck(iommu_mr);
>>>> +
>>>> +        iommu_idx = imrc->attrs_to_index(iommu_mr, attrs);
>>>> +        tcg_register_iommu_notifier(cpu, iommu_mr, iommu_idx);
>>>> +        /* We need all the permissions, so pass IOMMU_NONE so the IOMMU
>>>> +         * doesn't short-cut its translation table walk.
>> it is not clear to me why you don't use the access flag as you seem to
>> handle the perm fault after the translate() call.
> 
> We need to know all the permissions (because we'll cache the result
> in the TCG TLB and later use them for future read and write accesses),
> so we pass IOMMU_NONE.
> 
> My understanding from previous discussion is that the only
> reason to pass in some other access flag value is if you
> only care about one of read or write and want to allow the
> IOMMU to stop walking the page table early as soon as it decides
> it doesn't have permissions.

agreed. So you need to fetch the whole set of table permissions to
update the TLB. By the way where is the TLB updated?

Thanks

Eric
> 
> thanks
> -- PMM
> 

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 17/27] exec.c: Handle IOMMUs in address_space_translate_for_iotlb()
  2018-05-25  9:50         ` Auger Eric
@ 2018-05-25  9:59           ` Peter Maydell
  0 siblings, 0 replies; 114+ messages in thread
From: Peter Maydell @ 2018-05-25  9:59 UTC (permalink / raw)
  To: Auger Eric
  Cc: patches, QEMU Developers, qemu-arm, Paolo Bonzini,
	Alex Bennée, Richard Henderson

On 25 May 2018 at 10:50, Auger Eric <eric.auger@redhat.com> wrote:
> On 05/25/2018 10:52 AM, Peter Maydell wrote:
>> Once we've flushed the TLB it is empty and will have no cached
>> information from the IOMMU. So there's no point in flushing the
>> TLB again (which is expensive) until the next time a transaction
>> goes through the IOMMU and we're caching something from it.
> Ak OK. there is no finer granularity for TLB flush?

Yes, there is -- you can flush by (input) address; but I
opted to do a global flush, because it doesn't require
complicated tracking of which parts of the IOMMU's address
range we care about, and in general I expect IOMMU config
changes to be fairly rare:

+        /* Rather than trying to register interest in the specific part
+         * of the iommu's address space that we've accessed and then
+         * expand it later as subsequent accesses touch more of it, we
+         * just register interest in the whole thing, on the assumption
+         * that iommu reconfiguration will be rare.
+         */

We can always come back and revisit that if there turns
out to be a performance problem here in practice.

>> We need to know all the permissions (because we'll cache the result
>> in the TCG TLB and later use them for future read and write accesses),
>> so we pass IOMMU_NONE.
>>
>> My understanding from previous discussion is that the only
>> reason to pass in some other access flag value is if you
>> only care about one of read or write and want to allow the
>> IOMMU to stop walking the page table early as soon as it decides
>> it doesn't have permissions.
>
> agreed. So you need to fetch the whole set of table permissions to
> update the TLB. By the way where is the TLB updated?

tlb_set_page_with_attrs() calls address_space_translate_for_iotlb(),
which looks up what's at that address, including doing IOMMU
translations. Then tlb_set_page_with_attrs() fills in the TLB
data structure with the results.

thanks
-- PMM

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 00/27] iommu: support txattrs, support TCG execution, implement TZ MPC
  2018-05-21 14:03 [Qemu-devel] [PATCH 00/27] iommu: support txattrs, support TCG execution, implement TZ MPC Peter Maydell
                   ` (27 preceding siblings ...)
  2018-05-21 15:10 ` [Qemu-devel] [PATCH 00/27] iommu: support txattrs, support TCG execution, implement TZ MPC no-reply
@ 2018-05-30 16:58 ` Paolo Bonzini
  2018-05-31  9:54   ` Peter Maydell
  28 siblings, 1 reply; 114+ messages in thread
From: Paolo Bonzini @ 2018-05-30 16:58 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel
  Cc: Richard Henderson, Alex Bennée, patches

On 21/05/2018 16:03, Peter Maydell wrote:
> This patchset is a rather large one, but the first half is all
> fairly simple plumbing. It does four things:
>  * support IOMMUs that are aware of memory transaction attributes and
>    may generate different translations for different attributes
>  * support TCG execution out of memory which is behind an IOMMU
>  * implement the Arm TrustZone Memory Protection Controller
>    (which needs both the above features in the IOMMU core code)
>  * use the MPC in the mps2-an505 board

Go ahead and apply it through the ARM tree.  Thanks!

Paolo

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 23/27] hw/core/or-irq: Support more than 16 inputs to an OR gate
  2018-05-21 15:02     ` Peter Maydell
@ 2018-05-30 16:59       ` Paolo Bonzini
  2018-05-30 17:35         ` Peter Maydell
  0 siblings, 1 reply; 114+ messages in thread
From: Paolo Bonzini @ 2018-05-30 16:59 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Richard Henderson, qemu-arm, Alex Bennée, QEMU Developers, patches

On 21/05/2018 17:02, Peter Maydell wrote:
> On 21 May 2018 at 15:34, Paolo Bonzini <pbonzini@redhat.com> wrote:
>> Why do the levels have to be migrated at all?  It should be enough if
>> the IRQ level is either migrated manually, or restored (e.g. in
>> post_save callbacks) through other data that is migrated.
> This is standard behaviour for devices: they track their
> inbound irq/gpio lines, and then that becomes internal state for
> them that must be migrated.

But or_irq's input are another device's outbound lines, so tracking them
should not be necessary.  The other device would do it for or_irq.

Paolo

> If we didn't migrate the input line state, then after a migration
> the levels[] array would be all zeroes, and the next time a
> connected device signalled a high-to-low transition we'd take
> the output line low even if it should not be (because we'd have
> forgotten that some other input lines were high).
> 
> In a different world, the state would be in the qemu_irq line itself
> (in the same way that in hardware signal lines are their own state),
> but we can't get there from here.

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 23/27] hw/core/or-irq: Support more than 16 inputs to an OR gate
  2018-05-30 16:59       ` Paolo Bonzini
@ 2018-05-30 17:35         ` Peter Maydell
  2018-05-31 10:21           ` Paolo Bonzini
  0 siblings, 1 reply; 114+ messages in thread
From: Peter Maydell @ 2018-05-30 17:35 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Richard Henderson, qemu-arm, Alex Bennée, QEMU Developers, patches

On 30 May 2018 at 17:59, Paolo Bonzini <pbonzini@redhat.com> wrote:
> On 21/05/2018 17:02, Peter Maydell wrote:
>> On 21 May 2018 at 15:34, Paolo Bonzini <pbonzini@redhat.com> wrote:
>>> Why do the levels have to be migrated at all?  It should be enough if
>>> the IRQ level is either migrated manually, or restored (e.g. in
>>> post_save callbacks) through other data that is migrated.
>> This is standard behaviour for devices: they track their
>> inbound irq/gpio lines, and then that becomes internal state for
>> them that must be migrated.
>
> But or_irq's input are another device's outbound lines, so tracking them
> should not be necessary.  The other device would do it for or_irq.

There's no mechanism in qemu_irq for the destination end to ask
the source end about its current value. The information flow
is strictly one-way.

thanks
-- PMM

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 00/27] iommu: support txattrs, support TCG execution, implement TZ MPC
  2018-05-30 16:58 ` Paolo Bonzini
@ 2018-05-31  9:54   ` Peter Maydell
  2018-05-31 13:37     ` Peter Maydell
  0 siblings, 1 reply; 114+ messages in thread
From: Peter Maydell @ 2018-05-31  9:54 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: qemu-arm, QEMU Developers, Richard Henderson, Alex Bennée, patches

On 30 May 2018 at 17:58, Paolo Bonzini <pbonzini@redhat.com> wrote:
> On 21/05/2018 16:03, Peter Maydell wrote:
>> This patchset is a rather large one, but the first half is all
>> fairly simple plumbing. It does four things:
>>  * support IOMMUs that are aware of memory transaction attributes and
>>    may generate different translations for different attributes
>>  * support TCG execution out of memory which is behind an IOMMU
>>  * implement the Arm TrustZone Memory Protection Controller
>>    (which needs both the above features in the IOMMU core code)
>>  * use the MPC in the mps2-an505 board
>
> Go ahead and apply it through the ARM tree.  Thanks!

It needs a v2 (there are some patches that need fixing),
and some of the tail end of the patchset hasn't been reviewed,
and I'm not sure if we have consensus on the IOMMU API changes
completely yet. But if you're happy we're going in the right
direction I can apply 1-13 via target-arm.next (that's the
"plumb TxAttrs through various functions" patches). That will
reduce the size of the patchset and make conflicts less likely.

thanks
-- PMM

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 23/27] hw/core/or-irq: Support more than 16 inputs to an OR gate
  2018-05-30 17:35         ` Peter Maydell
@ 2018-05-31 10:21           ` Paolo Bonzini
  2018-05-31 10:50             ` Peter Maydell
  0 siblings, 1 reply; 114+ messages in thread
From: Paolo Bonzini @ 2018-05-31 10:21 UTC (permalink / raw)
  To: Peter Maydell
  Cc: qemu-arm, Alex Bennée, QEMU Developers, patches, Richard Henderson

On 30/05/2018 19:35, Peter Maydell wrote:
> On 30 May 2018 at 17:59, Paolo Bonzini <pbonzini@redhat.com> wrote:
>> On 21/05/2018 17:02, Peter Maydell wrote:
>>> On 21 May 2018 at 15:34, Paolo Bonzini <pbonzini@redhat.com> wrote:
>>>> Why do the levels have to be migrated at all?  It should be enough if
>>>> the IRQ level is either migrated manually, or restored (e.g. in
>>>> post_save callbacks) through other data that is migrated.
>>> This is standard behaviour for devices: they track their
>>> inbound irq/gpio lines, and then that becomes internal state for
>>> them that must be migrated.
>>
>> But or_irq's input are another device's outbound lines, so tracking them
>> should not be necessary.  The other device would do it for or_irq.
> 
> There's no mechanism in qemu_irq for the destination end to ask
> the source end about its current value. The information flow
> is strictly one-way.

On postload, the source must call qemu_set_irq and that will cause an
update of the or_irq, won't it?

Paolo

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 23/27] hw/core/or-irq: Support more than 16 inputs to an OR gate
  2018-05-31 10:21           ` Paolo Bonzini
@ 2018-05-31 10:50             ` Peter Maydell
  2018-05-31 11:50               ` Paolo Bonzini
  0 siblings, 1 reply; 114+ messages in thread
From: Peter Maydell @ 2018-05-31 10:50 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: qemu-arm, Alex Bennée, QEMU Developers, patches, Richard Henderson

On 31 May 2018 at 11:21, Paolo Bonzini <pbonzini@redhat.com> wrote:
> On 30/05/2018 19:35, Peter Maydell wrote:
>> On 30 May 2018 at 17:59, Paolo Bonzini <pbonzini@redhat.com> wrote:
>>> On 21/05/2018 17:02, Peter Maydell wrote:
>>>> On 21 May 2018 at 15:34, Paolo Bonzini <pbonzini@redhat.com> wrote:
>>>>> Why do the levels have to be migrated at all?  It should be enough if
>>>>> the IRQ level is either migrated manually, or restored (e.g. in
>>>>> post_save callbacks) through other data that is migrated.
>>>> This is standard behaviour for devices: they track their
>>>> inbound irq/gpio lines, and then that becomes internal state for
>>>> them that must be migrated.
>>>
>>> But or_irq's input are another device's outbound lines, so tracking them
>>> should not be necessary.  The other device would do it for or_irq.
>>
>> There's no mechanism in qemu_irq for the destination end to ask
>> the source end about its current value. The information flow
>> is strictly one-way.
>
> On postload, the source must call qemu_set_irq and that will cause an
> update of the or_irq, won't it?

No, calling qemu_set_irq in postload is a bug. (You don't know
which order the state of the source and destination devices is
restored, so asserting a signal in postload would have different
effects depending on whether the destination had already had
its state restored or not.) The system design relies on each
device keeping track of (and migrating) the state of the input
lines it cares about.

thanks
-- PMM

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 23/27] hw/core/or-irq: Support more than 16 inputs to an OR gate
  2018-05-31 10:50             ` Peter Maydell
@ 2018-05-31 11:50               ` Paolo Bonzini
  2018-05-31 11:59                 ` Peter Maydell
  0 siblings, 1 reply; 114+ messages in thread
From: Paolo Bonzini @ 2018-05-31 11:50 UTC (permalink / raw)
  To: Peter Maydell
  Cc: qemu-arm, Alex Bennée, QEMU Developers, patches, Richard Henderson

On 31/05/2018 12:50, Peter Maydell wrote:
> On 31 May 2018 at 11:21, Paolo Bonzini <pbonzini@redhat.com> wrote:
>> On 30/05/2018 19:35, Peter Maydell wrote:
>>> On 30 May 2018 at 17:59, Paolo Bonzini <pbonzini@redhat.com> wrote:
>>>> On 21/05/2018 17:02, Peter Maydell wrote:
>>>>> On 21 May 2018 at 15:34, Paolo Bonzini <pbonzini@redhat.com> wrote:
>>>>>> Why do the levels have to be migrated at all?  It should be enough if
>>>>>> the IRQ level is either migrated manually, or restored (e.g. in
>>>>>> post_save callbacks) through other data that is migrated.
>>>>> This is standard behaviour for devices: they track their
>>>>> inbound irq/gpio lines, and then that becomes internal state for
>>>>> them that must be migrated.
>>>>
>>>> But or_irq's input are another device's outbound lines, so tracking them
>>>> should not be necessary.  The other device would do it for or_irq.
>>>
>>> There's no mechanism in qemu_irq for the destination end to ask
>>> the source end about its current value. The information flow
>>> is strictly one-way.
>>
>> On postload, the source must call qemu_set_irq and that will cause an
>> update of the or_irq, won't it?
> 
> No, calling qemu_set_irq in postload is a bug. (You don't know
> which order the state of the source and destination devices is
> restored, so asserting a signal in postload would have different
> effects depending on whether the destination had already had
> its state restored or not.)

Hmm, I suppose the x86 world is a bit more "hierarchical" and you cannot
create a qemu_irq loop - and creating the sink always before the source
ensures that migration works fine with post_load.  I'm pretty sure that
there are devices that do that, and an interesting case (for the sake of
this thread) is the IOMMU, which prompted the introduction of
MigrationPriority.  Thanks for the lesson! :)

Maybe we should add your text to docs/devel/migration.rst, under "Device
ordering", because it explicitly mentions interrupt controllers.

Paolo

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 23/27] hw/core/or-irq: Support more than 16 inputs to an OR gate
  2018-05-31 11:50               ` Paolo Bonzini
@ 2018-05-31 11:59                 ` Peter Maydell
  0 siblings, 0 replies; 114+ messages in thread
From: Peter Maydell @ 2018-05-31 11:59 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: qemu-arm, Alex Bennée, QEMU Developers, patches, Richard Henderson

On 31 May 2018 at 12:50, Paolo Bonzini <pbonzini@redhat.com> wrote:
> On 31/05/2018 12:50, Peter Maydell wrote:
>> No, calling qemu_set_irq in postload is a bug. (You don't know
>> which order the state of the source and destination devices is
>> restored, so asserting a signal in postload would have different
>> effects depending on whether the destination had already had
>> its state restored or not.)
>
> Hmm, I suppose the x86 world is a bit more "hierarchical" and you cannot
> create a qemu_irq loop - and creating the sink always before the source
> ensures that migration works fine with post_load.  I'm pretty sure that
> there are devices that do that

If there are then they are broken, because that's not how
qemu_irqs work... (Similarly, you can't assert an irq
in a reset method, because of ordering problems.)

>, and an interesting case (for the sake of
> this thread) is the IOMMU, which prompted the introduction of
> MigrationPriority.  Thanks for the lesson! :)

This sounds like a workaround for a bug in the device implementation.
Devices shouldn't care about which order they're restored in.

thanks
-- PMM

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 00/27] iommu: support txattrs, support TCG execution, implement TZ MPC
  2018-05-31  9:54   ` Peter Maydell
@ 2018-05-31 13:37     ` Peter Maydell
  0 siblings, 0 replies; 114+ messages in thread
From: Peter Maydell @ 2018-05-31 13:37 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: qemu-arm, QEMU Developers, Richard Henderson, Alex Bennée, patches

On 31 May 2018 at 10:54, Peter Maydell <peter.maydell@linaro.org> wrote:
> On 30 May 2018 at 17:58, Paolo Bonzini <pbonzini@redhat.com> wrote:
>> Go ahead and apply it through the ARM tree.  Thanks!
>
> It needs a v2 (there are some patches that need fixing),
> and some of the tail end of the patchset hasn't been reviewed,
> and I'm not sure if we have consensus on the IOMMU API changes
> completely yet. But if you're happy we're going in the right
> direction I can apply 1-13 via target-arm.next (that's the
> "plumb TxAttrs through various functions" patches). That will
> reduce the size of the patchset and make conflicts less likely.

I'm putting patches 1-13 (initial plumbing) and 22 (adding
VMSTATE_BOOL_SUB_ARRAY) into target-arm.next.

The rest will need a respin to fix minor nits and some
conflicts with things that are now in master.

thanks
-- PMM

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 15/27] iommu: Add IOMMU index argument to notifier APIs
  2018-05-23  9:08   ` Alex Bennée
@ 2018-06-04 13:03     ` Peter Maydell
  2018-06-04 15:09       ` Alex Bennée
  0 siblings, 1 reply; 114+ messages in thread
From: Peter Maydell @ 2018-06-04 13:03 UTC (permalink / raw)
  To: Alex Bennée
  Cc: qemu-arm, QEMU Developers, patches, Paolo Bonzini, Richard Henderson

On 23 May 2018 at 10:08, Alex Bennée <alex.bennee@linaro.org> wrote:
>
> Peter Maydell <peter.maydell@linaro.org> writes:
>
>> Add support for multiple IOMMU indexes to the IOMMU notifier APIs.
>> When initializing a notifier with iommu_notifier_init(), the caller
>> must pass the IOMMU index that it is interested in. When a change
>> happens, the IOMMU implementation must pass
>> memory_region_notify_iommu() the IOMMU index that has changed and
>> that notifiers must be called for.
>>
>> IOMMUs which support only a single index don't need to change.
>> Callers which only really support working with IOMMUs with a single
>> index can use the result of passing MEMTXATTRS_UNSPECIFIED to
>> memory_region_iommu_attrs_to_index().
>>
>> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
>> ---
>>  include/exec/memory.h    | 11 ++++++++++-
>>  hw/i386/intel_iommu.c    |  4 ++--
>>  hw/ppc/spapr_iommu.c     |  2 +-
>>  hw/s390x/s390-pci-inst.c |  4 ++--
>>  hw/vfio/common.c         |  6 +++++-
>>  hw/virtio/vhost.c        |  7 ++++++-
>>  memory.c                 |  8 +++++++-
>>  7 files changed, 33 insertions(+), 9 deletions(-)
>>
>> diff --git a/include/exec/memory.h b/include/exec/memory.h
>> index f6226fb263..4e6b125add 100644
>> --- a/include/exec/memory.h
>> +++ b/include/exec/memory.h
>> @@ -71,6 +71,7 @@ struct IOMMUTLBEntry {
>>      hwaddr           iova;
>>      hwaddr           translated_addr;
>>      hwaddr           addr_mask;  /* 0xfff = 4k translation */
>> +    int              iommu_idx;
>>      IOMMUAccessFlags perm;
>>  };
>>
>> @@ -98,18 +99,21 @@ struct IOMMUNotifier {
>>      /* Notify for address space range start <= addr <= end */
>>      hwaddr start;
>>      hwaddr end;
>> +    int iommu_idx;
>
> Its a minor thing but are we ever expecting iommu_idx to ever be
> negative?

Coming back to this one -- no, we don't expect negative iommu_idxs.
But on the other hand we don't ever expect negative TCG mmu_indexes
either, and we use 'int' for those...

thanks
-- PMM

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 15/27] iommu: Add IOMMU index argument to notifier APIs
  2018-06-04 13:03     ` Peter Maydell
@ 2018-06-04 15:09       ` Alex Bennée
  2018-06-04 15:23         ` Peter Maydell
  0 siblings, 1 reply; 114+ messages in thread
From: Alex Bennée @ 2018-06-04 15:09 UTC (permalink / raw)
  To: Peter Maydell
  Cc: qemu-arm, QEMU Developers, patches, Paolo Bonzini, Richard Henderson


Peter Maydell <peter.maydell@linaro.org> writes:

> On 23 May 2018 at 10:08, Alex Bennée <alex.bennee@linaro.org> wrote:
>>
>> Peter Maydell <peter.maydell@linaro.org> writes:
>>
>>> Add support for multiple IOMMU indexes to the IOMMU notifier APIs.
>>> When initializing a notifier with iommu_notifier_init(), the caller
>>> must pass the IOMMU index that it is interested in. When a change
>>> happens, the IOMMU implementation must pass
>>> memory_region_notify_iommu() the IOMMU index that has changed and
>>> that notifiers must be called for.
>>>
>>> IOMMUs which support only a single index don't need to change.
>>> Callers which only really support working with IOMMUs with a single
>>> index can use the result of passing MEMTXATTRS_UNSPECIFIED to
>>> memory_region_iommu_attrs_to_index().
>>>
>>> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
>>> ---
>>>  include/exec/memory.h    | 11 ++++++++++-
>>>  hw/i386/intel_iommu.c    |  4 ++--
>>>  hw/ppc/spapr_iommu.c     |  2 +-
>>>  hw/s390x/s390-pci-inst.c |  4 ++--
>>>  hw/vfio/common.c         |  6 +++++-
>>>  hw/virtio/vhost.c        |  7 ++++++-
>>>  memory.c                 |  8 +++++++-
>>>  7 files changed, 33 insertions(+), 9 deletions(-)
>>>
>>> diff --git a/include/exec/memory.h b/include/exec/memory.h
>>> index f6226fb263..4e6b125add 100644
>>> --- a/include/exec/memory.h
>>> +++ b/include/exec/memory.h
>>> @@ -71,6 +71,7 @@ struct IOMMUTLBEntry {
>>>      hwaddr           iova;
>>>      hwaddr           translated_addr;
>>>      hwaddr           addr_mask;  /* 0xfff = 4k translation */
>>> +    int              iommu_idx;
>>>      IOMMUAccessFlags perm;
>>>  };
>>>
>>> @@ -98,18 +99,21 @@ struct IOMMUNotifier {
>>>      /* Notify for address space range start <= addr <= end */
>>>      hwaddr start;
>>>      hwaddr end;
>>> +    int iommu_idx;
>>
>> Its a minor thing but are we ever expecting iommu_idx to ever be
>> negative?
>
> Coming back to this one -- no, we don't expect negative iommu_idxs.
> But on the other hand we don't ever expect negative TCG mmu_indexes
> either, and we use 'int' for those...

That's a clean-up right there ;-)

As I said it's a minor thing but I generally favour clearest type for
the range you are going to see. That said the enum stuff on the older
clangs did confuse me so there is that...

--
Alex Bennée

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [Qemu-devel] [PATCH 15/27] iommu: Add IOMMU index argument to notifier APIs
  2018-06-04 15:09       ` Alex Bennée
@ 2018-06-04 15:23         ` Peter Maydell
  0 siblings, 0 replies; 114+ messages in thread
From: Peter Maydell @ 2018-06-04 15:23 UTC (permalink / raw)
  To: Alex Bennée
  Cc: qemu-arm, QEMU Developers, patches, Paolo Bonzini, Richard Henderson

On 4 June 2018 at 16:09, Alex Bennée <alex.bennee@linaro.org> wrote:
>
> Peter Maydell <peter.maydell@linaro.org> writes:
>
>> On 23 May 2018 at 10:08, Alex Bennée <alex.bennee@linaro.org> wrote:
>>> Its a minor thing but are we ever expecting iommu_idx to ever be
>>> negative?
>>
>> Coming back to this one -- no, we don't expect negative iommu_idxs.
>> But on the other hand we don't ever expect negative TCG mmu_indexes
>> either, and we use 'int' for those...
>
> That's a clean-up right there ;-)
>
> As I said it's a minor thing but I generally favour clearest type for
> the range you are going to see. That said the enum stuff on the older
> clangs did confuse me so there is that...

I prefer the "don't use unsigned unless you need the
unsigned-integer semantics" approach. (For instance most
loop indexes won't ever be negative, but "int i" is the
usual thing there.)

thanks
-- PMM

^ permalink raw reply	[flat|nested] 114+ messages in thread

end of thread, other threads:[~2018-06-04 15:23 UTC | newest]

Thread overview: 114+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-05-21 14:03 [Qemu-devel] [PATCH 00/27] iommu: support txattrs, support TCG execution, implement TZ MPC Peter Maydell
2018-05-21 14:03 ` [Qemu-devel] [PATCH 01/27] memory.h: Improve IOMMU related documentation Peter Maydell
2018-05-21 19:46   ` Richard Henderson
2018-05-22  9:16   ` Alex Bennée
2018-05-22 11:40   ` Auger Eric
2018-05-21 14:03 ` [Qemu-devel] [PATCH 02/27] Make tb_invalidate_phys_addr() take a MemTxAttrs argument Peter Maydell
2018-05-21 23:54   ` Richard Henderson
2018-05-22  9:21   ` Alex Bennée
2018-05-21 14:03 ` [Qemu-devel] [PATCH 03/27] Make address_space_translate{, _cached}() " Peter Maydell
2018-05-22 10:49   ` Alex Bennée
2018-05-22 16:12   ` Richard Henderson
2018-05-21 14:03 ` [Qemu-devel] [PATCH 04/27] Make address_space_map() " Peter Maydell
2018-05-22 10:49   ` Alex Bennée
2018-05-22 16:13   ` Richard Henderson
2018-05-21 14:03 ` [Qemu-devel] [PATCH 05/27] Make address_space_access_valid() " Peter Maydell
2018-05-22 10:50   ` Alex Bennée
2018-05-22 16:14   ` Richard Henderson
2018-05-21 14:03 ` [Qemu-devel] [PATCH 06/27] Make flatview_extend_translation() " Peter Maydell
2018-05-22 10:56   ` Alex Bennée
2018-05-22 16:15   ` Richard Henderson
2018-05-21 14:03 ` [Qemu-devel] [PATCH 07/27] Make memory_region_access_valid() " Peter Maydell
2018-05-22 10:57   ` Alex Bennée
2018-05-22 16:17   ` Richard Henderson
2018-05-21 14:03 ` [Qemu-devel] [PATCH 08/27] Make MemoryRegion valid.accepts callback " Peter Maydell
2018-05-22 10:58   ` Alex Bennée
2018-05-22 16:20   ` Richard Henderson
2018-05-21 14:03 ` [Qemu-devel] [PATCH 09/27] Make flatview_access_valid() " Peter Maydell
2018-05-22 10:58   ` Alex Bennée
2018-05-22 16:33   ` Richard Henderson
2018-05-22 16:37     ` Peter Maydell
2018-05-21 14:03 ` [Qemu-devel] [PATCH 10/27] Make flatview_translate() " Peter Maydell
2018-05-22 10:58   ` Alex Bennée
2018-05-22 16:33   ` Richard Henderson
2018-05-21 14:03 ` [Qemu-devel] [PATCH 11/27] Make address_space_get_iotlb_entry() " Peter Maydell
2018-05-22 11:00   ` Alex Bennée
2018-05-22 17:29   ` Richard Henderson
2018-05-21 14:03 ` [Qemu-devel] [PATCH 12/27] Make flatview_do_translate() " Peter Maydell
2018-05-22 11:00   ` Alex Bennée
2018-05-22 17:29   ` Richard Henderson
2018-05-21 14:03 ` [Qemu-devel] [PATCH 13/27] Make address_space_translate_iommu " Peter Maydell
2018-05-22 11:00   ` Alex Bennée
2018-05-22 17:30   ` Richard Henderson
2018-05-21 14:03 ` [Qemu-devel] [PATCH 14/27] iommu: Add IOMMU index concept to IOMMU API Peter Maydell
2018-05-22  3:03   ` Peter Xu
2018-05-22  8:40     ` Peter Maydell
2018-05-22 11:02       ` Peter Xu
2018-05-22 11:11         ` Peter Maydell
2018-05-23  1:06           ` Peter Xu
2018-05-23 11:47             ` Peter Maydell
2018-05-24  6:23               ` Peter Xu
2018-05-24 10:54                 ` Peter Maydell
2018-05-25  2:50                   ` Peter Xu
2018-05-25  9:27                   ` Auger Eric
2018-05-25  9:34                     ` Peter Maydell
2018-05-22 12:58   ` Auger Eric
2018-05-22 13:22     ` Peter Maydell
2018-05-22 14:11       ` Auger Eric
2018-05-22 14:19         ` Peter Maydell
2018-05-22 14:22           ` Auger Eric
2018-05-22 17:42   ` Richard Henderson
2018-05-22 17:51     ` Peter Maydell
2018-05-22 17:52       ` Richard Henderson
2018-05-21 14:03 ` [Qemu-devel] [PATCH 15/27] iommu: Add IOMMU index argument to notifier APIs Peter Maydell
2018-05-22 17:45   ` Richard Henderson
2018-05-23  9:08   ` Alex Bennée
2018-06-04 13:03     ` Peter Maydell
2018-06-04 15:09       ` Alex Bennée
2018-06-04 15:23         ` Peter Maydell
2018-05-24 15:29   ` Auger Eric
2018-05-24 17:03     ` Peter Maydell
2018-05-24 19:13       ` Auger Eric
2018-05-21 14:03 ` [Qemu-devel] [PATCH 16/27] iommu: Add IOMMU index argument to translate method Peter Maydell
2018-05-22 18:06   ` Richard Henderson
2018-05-23  9:11   ` Alex Bennée
2018-05-21 14:03 ` [Qemu-devel] [PATCH 17/27] exec.c: Handle IOMMUs in address_space_translate_for_iotlb() Peter Maydell
2018-05-23  9:51   ` Alex Bennée
2018-05-23 11:52     ` Peter Maydell
2018-05-24 19:54     ` Auger Eric
2018-05-25  8:52       ` Peter Maydell
2018-05-25  9:50         ` Auger Eric
2018-05-25  9:59           ` Peter Maydell
2018-05-21 14:03 ` [Qemu-devel] [PATCH 18/27] hw/misc/tz-mpc.c: Implement the Arm TrustZone Memory Protection Controller Peter Maydell
2018-05-22 11:30   ` Auger Eric
2018-05-22 11:56     ` Peter Maydell
2018-05-22 12:23       ` Auger Eric
2018-05-23 10:41   ` Alex Bennée
2018-05-21 14:03 ` [Qemu-devel] [PATCH 19/27] hw/misc/tz-mpc.c: Implement registers Peter Maydell
2018-05-23 10:44   ` Alex Bennée
2018-05-21 14:03 ` [Qemu-devel] [PATCH 20/27] hw/misc/tz-mpc.c: Implement correct blocked-access behaviour Peter Maydell
2018-05-23 10:49   ` Alex Bennée
2018-05-23 11:54     ` Peter Maydell
2018-05-21 14:03 ` [Qemu-devel] [PATCH 21/27] hw/misc/tz_mpc.c: Honour the BLK_LUT settings in translate Peter Maydell
2018-05-21 14:03 ` [Qemu-devel] [PATCH 22/27] vmstate.h: Provide VMSTATE_BOOL_SUB_ARRAY Peter Maydell
2018-05-23 11:01   ` Alex Bennée
2018-05-21 14:03 ` [Qemu-devel] [PATCH 23/27] hw/core/or-irq: Support more than 16 inputs to an OR gate Peter Maydell
2018-05-21 14:34   ` Paolo Bonzini
2018-05-21 15:02     ` Peter Maydell
2018-05-30 16:59       ` Paolo Bonzini
2018-05-30 17:35         ` Peter Maydell
2018-05-31 10:21           ` Paolo Bonzini
2018-05-31 10:50             ` Peter Maydell
2018-05-31 11:50               ` Paolo Bonzini
2018-05-31 11:59                 ` Peter Maydell
2018-05-21 14:03 ` [Qemu-devel] [PATCH 24/27] hw/misc/iotkit-secctl.c: Implement SECMPCINTSTATUS Peter Maydell
2018-05-21 14:04 ` [Qemu-devel] [PATCH 25/27] hw/arm/iotkit: Instantiate MPC Peter Maydell
2018-05-23 11:38   ` Alex Bennée
2018-05-21 14:04 ` [Qemu-devel] [PATCH 26/27] hw/arm/iotkit: Wire up MPC interrupt lines Peter Maydell
2018-05-23 11:39   ` Alex Bennée
2018-05-21 14:04 ` [Qemu-devel] [PATCH 27/27] hw/arm/mps2-tz.c: Instantiate MPCs Peter Maydell
2018-05-23 11:41   ` Alex Bennée
2018-05-21 15:10 ` [Qemu-devel] [PATCH 00/27] iommu: support txattrs, support TCG execution, implement TZ MPC no-reply
2018-05-30 16:58 ` Paolo Bonzini
2018-05-31  9:54   ` Peter Maydell
2018-05-31 13:37     ` Peter Maydell

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.