All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v11 00/34] arm64: Dom0 ITS emulation
@ 2017-06-09 17:41 Andre Przywara
  2017-06-09 17:41 ` [PATCH v11 01/34] ARM: vGIC: avoid rank lock when reading priority Andre Przywara
                   ` (34 more replies)
  0 siblings, 35 replies; 71+ messages in thread
From: Andre Przywara @ 2017-06-09 17:41 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

Hi,

fixes to v10, with their number getting eventually smaller ;-)
The same restriction as for the previous versions  still apply: the locking
is considered somewhat insufficient and will be fixed by an upcoming rework.

Patch 01/34 was reworked to properly synchronize access to the priority
in a lock-less fashion. This should be back-ported to 4.9.
The former patch 12/32 ("enable ITS and LPIs on the host") was moved up-front
and split to allow back-porting the new 02/34 to Xen 4.9, which is broken
if the preliminary ITS support is configured in and the machine advertises
an ITS in the device tree.

No big changes this time: some bugs fixed (many thanks to Julien for
proper testing!), some extended comments and some improvements to better
protect parallel accesses. For a detailed changelog see below.

I added Acked-by: and Reviewed-by: tags, but refrained from doing so
for Julien's tags for patch 18/34 and 20/34, since I changed them slightly.

Cheers,
Andre

----------------------------------
This series adds support for emulation of an ARM GICv3 ITS interrupt
controller. For hardware which relies on the ITS to provide interrupts for
its peripherals this code is needed to get a machine booted into Dom0 at
all. ITS emulation for DomUs is only really useful with PCI passthrough,
which is not yet available for ARM. It is expected that this feature
will be co-developed with the ITS DomU code. However this code drop here
considered DomU emulation already, to keep later architectural changes
to a minimum.

This is technical preview version to allow early testing of the feature.
Things not (properly) addressed in this release:
- There is only support for Dom0 at the moment. DomU support is only really
useful with PCI passthrough, which is not there yet for ARM.
- The MOVALL command is not emulated. In our case there is really nothing
to do here. We might need to revisit this in the future for DomU support.
- The INVALL command might need some rework to be more efficient. Currently
we iterate over all mapped LPIs, which might take a bit longer.
- Indirect tables are not supported. This affects both the host and the
virtual side.
- The ITS tables inside (Dom0) guest memory cannot easily be protected
at the moment (without restricting access to Xen as well). So for now
we trust Dom0 not to touch this memory (which the spec forbids as well).
- With malicious guests (DomUs) there is a possibility of an interrupt
storm triggered by a device. We would need to investigate what that means
for Xen and if there is a nice way to prevent this. Disabling the LPI on
the host side would require command queuing, which has its downsides to
be issued during runtime.
- Dom0 should make sure that the ITS resources (number of LPIs, devices,
events) later handed to a DomU are really limited, as a large number of
them could mean much time spend in Xen to initialize, free or handle those.
It is expected that the toolstack sets up a tailored ITS with just enough
resources to accommodate the needs of the actual passthrough-ed device(s).
- The command queue locking is currently suboptimal and should be made more
fine-grained in the future, if possible.
- Provide support for running with an IOMMU, to map the doorbell page
to all devices.


Some generic design principles:

* The current GIC code statically allocates structures for each supported
IRQ (both for the host and the guest), which due to the potentially
millions of LPI interrupts is not feasible to copy for the ITS.
So we refrain from introducing the ITS as a first class Xen interrupt
controller, also we don't hold struct irq_desc's or struct pending_irq's
for each possible LPI.
Fortunately LPIs are only interesting to guests, so we get away with
storing only the virtual IRQ number and the guest VCPU for each allocated
host LPI, which can be stashed into one uint64_t. This data is stored in
a two-level table, which is both memory efficient and quick to access.
We hook into the existing IRQ handling and VGIC code to avoid accessing
the normal structures, providing alternative methods for getting the
needed information (priority, is enabled?) for LPIs.
Whenever a guest maps a device, we allocate the maximum required number
of struct pending_irq's, so that any triggering LPI can find its data
structure. Upon the guest actually mapping the LPI, this pointer to the
corresponding pending_irq gets entered into a radix tree, so that it can
be quickly looked up.

* On the guest side we (later will) have to deal with malicious guests
trying to hog Xen with mapping requests for a lot of LPIs, for instance.
As the ITS actually uses system memory for storing status information,
we use this memory (which the guest has to provide) to naturally limit
a guest. Whenever we need information from any of the ITS tables, we
temporarily map them (which is cheap on arm64) and copy the required data.

* An obvious approach to handling some guest ITS commands would be to
propagate them to the host, for instance to map devices and LPIs and
to enable or disable LPIs.
However this (later with DomU support) will create an attack vector, as
a malicious guest could try to fill the host command queue with
propagated commands.
So we try to avoid this situation: Dom0 sending a device mapping (MAPD)
command is the only time we allow queuing commands to the host ITS command
queue, as this seems to be the only reliable way of getting the
required information at the moment. However at the same time we map all
events to LPIs already, also enable them. This avoids sending commands
later at runtime, as we can deal with mappings and LPI enabling/disabling
internally.

To accomodate the tech preview nature of this feature at the moment, there
is a Kconfig option to enable it. Also it is supported on arm64 only, which
will most likely not change in the future.
This leads to some hideous constructs like an #ifdef'ed header file with
empty function stubs to accomodate arm32 and non-ITS builds, which share
some generic code paths with the ITS emulation.
The number of supported LPIs can be limited on the command line, in case
the number reported by the hardware is too high. As Xen cannot foresee how
many interrupts the guests will need, we cater for as many as possible.
The command line parameter is called max-lpi-bits and expresses the number
of bits required to hold an interrupt ID. It defaults to 20, if that is
lower than the number supported by the hardware.

This code boots Dom0 on an ARM Fast Model with ITS support. I tried to
address the issues seen by people running the previous versions on real
hardware, though couldn't verify this here for myself.
So any testing, bug reports (and possibly even fixes) are very welcome.

The code can also be found on the its/v11 branch here:
git://linux-arm.org/xen-ap.git
http://www.linux-arm.org/git?p=xen-ap.git;a=shortlog;h=refs/heads/its/v11

Cheers,
Andre

Changelog v10 ... v11:
- [01/34]: use proper ACCESS_ONCE wrappers for all users
- [02/34]: split of v9-12/32 for backporting
- [03/34]: remainder of splitting v9-12/32
- [04/34]: extend comment to justify 10 INITD bits
- [05/34]: swapped place with former 04/32 to fix temporary deadlock
- [06/34]: swapped place with former 03/32 to fix temporary deadlock
- [08/34]: update commit message
- [10/34]: remove unneeded p->lr initialisation
- [11/34]: replace read_atomic with ACCESS_ONCE
- [13/34]: split of former 11/32: remove no longer needed vCPU ID in host LPI
- [14/34]: export inject_lpi, fix lock-less access to vCPU ID
- [18/34]: fix commit message, add one more memory barrier and comment
- [19/34]: fix its_cmd_mask_field(), dump ITS command on error
- [20/34]: drop lock-taking versions of {read,write}_itte, drop optional vCPU
           parameter to write_itte(), remove sanity checks (dony by callers)
- [21/34]: fix "veventid" parameter name
- [22/34]: explicitly take lock around read_itte, use vgic_vcpu_inject_lpi()
- [25/34]: fix "veventid" parameter name
- [26/34]: add unlikely() hints
- [27/34]: remove unneeded read_atomic(), explicitly sanitize collection
- [28/34]: extend IRQ migration comment
- [30/34]: protects against not valid property table
- [31/34]: protects against not valid property table, fix error propagation

Changelog v9 ... v10:
no changes to 06, 07, 12, 15, 20, 29, 30, 32
- [01/32]: fix for rank lock deadlock as posted before
- [02/32]: replace arbitrary 16 bits for DomU interrupt IDs with 10 bits
- [03/32]: handle functions not dealing with LPIs as well
- [04/32]: new patch to rename gic_remove_from_queues and remove lock
- [05/32]: new patch to introduce helper for removing IRQs from the VGIC
- [06/32]: adapt to previous changes
- [08/32]: use memset to clear the whole structure
- [09/32]: split off from former 05/28
- [10/32]: moved up front, initialize VCPU ID
- [11/32]: remove VCPU ID from host entry, rework LPI injection, moved
           out part dealing with LPI priority caching
- [13/32]: add a hint about boolean variables
- [14/32]: fix bool_t type usage
- [16/32]: replace magic value, always use intid_bits for TYPER generation,
           add memory barrier
- [17/32]: add comments about ITS table layout, remove le64_to_cpu(),
           simplify CTLR read and remove lock, use atomic read and add comment
           in CREADR read, add TODO and ASSERT about crafting ITS tables,
           add empty lines in switch/case, move code block
- [18/32]: consistent use of data types, comments moved out to earlier patch
- [19/32]: fold in get_host_lpi(), rename veventid identifier
- [21/32]: move variable assignment
- [22/32]: add TODO locking comment, use new gic_remove_irq() function
- [23/32]: remove no longer needed VCPU ID from host LPI functions, add
           locking TODO, use goto out
- [24/32]: explain reason for LR check, make LRs unsigned, move PRISTINE
           check into one place
- [25/32]: mention MAPI, remove VCPU ID from host LPI updates, use atomic
           write for priority update, remove outdated comment, explain
           error handling path, check for valid property table
- [26/32]: remove update of VCPU ID in the host_lpi structure, add locking TODO
- [27/32]: fix error path
- [28/32]: add comment about physical LPI, use generic function to remove IRQ,
           remove redundant clear_bit
- [31/32]: make vgic_v3_its_init_virtual() static (and move it), move comment,
           remove unneeded call to vgic_v3_its_free_domain()

Changelog v8 ... v9:
- [01/28]: initialize number of interrupt IDs for DomUs also
- [02/28]: move priority reading back up front
- [03/28]: enumerate all call sites in commit message, add ASSERTs,
           add "unlikely" hints, avoid skipping ASSERTs, add comment to
           irq_to_pending() definition
- [04/28]: explain expectation of device state while destroying domain
- [05/28]: document case of invalid LPI, change dummy priority to 0xff
- [08/28]: check cross page boundary condition early in function
- [10/28]: initialize status and lr member as well
- [11/28]: check lpi_vcpu_id to cover all virtual CPUs
- [12/28]: add spin lock ASSERT
- [13/28]: introduce types for our ITS table entries, fix error messages
- [14/28]: use new ITS table entry types
- [15/28]: new patch to introduce pending_irq lookup function
- [17/28]: verify size of collection table entry
- [18/28]: use new pending_irq lookup function
- [19/28]: use new pending_irq lookup function, collection table type and
           vgic_init_pending_irq, add Dom0 ASSERT and unmap devices for DomUs
- [20/28]: document PRISTINE_LPI flag, fix typo, avoid double insertion of
           the same LPI into different LRs
- [21/28]: use new pending_irq lookup function, avoid explict LPI number
           parameter
- [22/28]: add physical affinity TODO, use new table type and pending_irq
           lookup function, fix error message
- [24/28]: use pending_irq lookup function, drop explicit LPI number parameter
- [25/28]: drop explicit LPI number parameter
- [27/28]: use new ITS table entry type

Changelog v7 ... v8:
- drop list parameter and rename to gicv3_its_make_hwdwom_dt_nodes()
- remove rebase artifacts
- add irq_enter/irq_exit() calls
- propagates number of host LPIs and number of event IDs to Dom0
- add proper coverage of all addresses in ITS MMIO handler
- avoid vcmd_lock for CBASER writes
- fix missing irqsave/irqrestore on VGIC VCPU lock
- move struct pending_irq use under the VGIC VCPU lock
- protect gic_raise_guest_irq() against NULL pending_irq
- improve device and collection table entry size documentation
- count number of ITSes to increase mmio_count
- rework MAPD, DISCARD, MAPTI and MOVI to take proper locks
- properly rollback failing MAPD and MAPTI calls
- rework functions to update property table
- return error on vgic_access_guest_memory crossing page boundary
- make sure CREADR access is atomic

Changelog v5 ... v6:
- reordered patches to allow splitting the series
- introduced functions later to avoid warnings on intermediate builds
- refactored common code changes into separate patches
- dropped GENMASK_ULL and BIT_ULL (both patches and their usage later)
- rework locking in MMIO register reads and writes
- protect new code from being executed without an ITS being configured
- fix vgic_access_guest_memory (now a separate patch)
- some more comments and TODOs

Changelog v4 ... v5:
- adding many comments
- spinlock asserts
- rename r_host_lpis to max_host_lpi_ids
- remove max_its_device_bits command line
- add warning on high number of LPIs
- avoid potential leak on host MAPD
- properly handle nr_events rounding
- remove unmap_all_devices(), replace with ASSERT
- add barriers for (lockless) host LPI lookups
- add proper locking in ITS and redist MMIO register handling
- rollback failing device mapping
- fix various printks
- add vgic_access_guest_memory() and use it
- (getting rid of page mapping functions and helpers)
- drop table mapping / unmapping on redist/ITS enable/disable
- minor reworks in functions as per review comments
- fix ITS enablement check
- move lpi_to_pending() and lpi_get_priority() to vgic_ops
- move do_LPI() to gic_hw_ops
- whitespace and hard tabs fixes
- introduce ITS domain init function (and use it for the rbtree)
- enable IRQs around do_LPI
- implement TODOs for later optimizations
- add "v" prefix to variables holding virtual properties
- provide locked and normal versions of read/write_itte
- only CLEAR LPI if not already guest visible (plus comment)
- update LPI property on MAPTI
- store vcpu_id in pending_irq for LPIs (helps INVALL)
- improve INVALL implementation to only cover LPIs on this VCPU
- improve virtual BASE register initialization
- limit number of virtual LPIs to 24 bits (Linux bug at 32??)
- only inject LPIs if redistributor is actually enabled

Changelog v3 .. v4:
- make HAS_ITS depend on EXPERT
- introduce new patch 02 to initialize host ITS early
- fix cmd_lock init position
- introduce warning on high number of LPI allocations
- various int -> unsigned fixes
- adding and improving comments
- rate limit ITS command queue full msg
- drop unneeded checks
- validate against allowed number of device IDs
- avoid memory leaks when removing devices
- improve algorithm for finding free host LPI
- convert unmap_all_devices from goto to while loop
- add message on remapping ITS device
- name virtual device / event IDs properly
- use atomic read when reading ITT entry

Changelog v2 .. v3:
- preallocate struct pending_irq's
- map ITS and redistributor tables only on demand
- store property, enable and pending bit in struct pending_irq
- improve error checking and handling
- add comments

Changelog v1 .. v2:
- clean up header file inclusion
- rework host ITS table allocation: observe attributes, many fixes
- remove patch 1 to export __flush_dcache_area, use existing function instead
- use number of LPIs internally instead of number of bits
- keep host_its_list as private as possible
- keep struct its_devices private
- rework gicv3_its_map_guest_devices
- fix rbtree issues
- more error handling and propagation
- cope with GICv4 implementations (but no virtual LPI features!)
- abstract host and guest ITSes by using doorbell addresses
- join per-redistributor variables into one per-CPU structure
- fix data types (unsigned int)
- many minor bug fixes

(Rough) changelog RFC-v2 .. v1:
- split host ITS driver into gic-v3-lpi.c and gic-v3-its.c part
- rename virtual ITS driver file to vgic-v3-its.c
- use macros and named constants for all magic numbers
- use atomic accessors for accessing the host LPI data
- remove leftovers from connecting virtual and host ITSes
- bail out if host ITS is disabled in the DT
- rework map/unmap_guest_pages():
    - split off p2m part as get/put_guest_pages (to be done on allocation)
    - get rid of vmap, using map_domain_page() instead
- delay allocation of virtual tables until actual LPI/ITS enablement
- properly size both virtual and physical tables upon allocation
- fix put_domain() locking issues in physdev_op and LPI handling code
- add and extend comments in various areas
- fix lotsa coding style and white space issues, including comment style
- add locking to data structures not yet covered
- fix various locking issues
- use an rbtree to deal with ITS devices (instead of a list)
- properly handle memory attributes for ITS tables
- handle cacheable/non-cacheable ITS table mappings
- sanitize guest provided ITS/LPI table attributes
- fix breakage on non-GICv2 compatible host GICv3 controllers
- add command line parameters on top of Kconfig options
- properly wait for an ITS to become quiescient before enabling it
- handle host ITS command queue errors
- actually wait for host ITS command completion (READR==WRITER)
- fix ARM32 compilation
- various patch splits and reorderings

Andre Przywara (33):
  ARM: vGIC: avoid rank lock when reading priority
  ARM: GICv3: enable ITS on the host
  ARM: GICv3: enable LPIs on the host
  ARM: GICv3: setup number of LPI bits for a GICv3 guest
  ARM: vGIC: rework gic_remove_from_queues()
  ARM: vGIC: move irq_to_pending() calls under the VGIC VCPU lock
  ARM: vGIC: introduce gic_remove_irq()
  ARM: GIC: Add checks for NULL pointer pending_irq's
  ARM: GICv3: introduce separate pending_irq structs for LPIs
  ARM: GIC: export and extend vgic_init_pending_irq()
  ARM: vGIC: cache virtual LPI priority in struct pending_irq
  ARM: vGIC: add LPI VCPU ID to struct pending_irq
  ARM: GIC: ITS: remove no longer needed VCPU ID in host LPI entry
  ARM: GICv3: forward pending LPIs to guests
  ARM: vGICv3: handle virtual LPI pending and property tables
  ARM: vGICv3: re-use vgic_reg64_check_access
  ARM: vGIC: advertise LPI support
  ARM: vITS: add command handling stub and MMIO emulation
  ARM: vITS: introduce translation table walks
  ARM: vITS: provide access to struct pending_irq
  ARM: vITS: handle INT command
  ARM: vITS: handle MAPC command
  ARM: vITS: handle CLEAR command
  ARM: vITS: handle MAPD command
  ARM: GICv3: handle unmapped LPIs
  ARM: vITS: handle MAPTI/MAPI command
  ARM: vITS: handle MOVI command
  ARM: vITS: handle DISCARD command
  ARM: vITS: handle INV command
  ARM: vITS: handle INVALL command
  ARM: vITS: increase mmio_count for each ITS
  ARM: vITS: create and initialize virtual ITSes for Dom0
  ARM: vITS: create ITS subnodes for Dom0 DT

Vijaya Kumar K (1):
  ARM: introduce vgic_access_guest_memory()

 xen/arch/arm/gic-v2.c            |    7 +
 xen/arch/arm/gic-v3-its.c        |  180 +++++
 xen/arch/arm/gic-v3-lpi.c        |   99 ++-
 xen/arch/arm/gic-v3.c            |   29 +-
 xen/arch/arm/gic.c               |  102 ++-
 xen/arch/arm/vgic-v2.c           |   28 +-
 xen/arch/arm/vgic-v3-its.c       | 1482 +++++++++++++++++++++++++++++++++++++-
 xen/arch/arm/vgic-v3.c           |  327 ++++++++-
 xen/arch/arm/vgic.c              |  146 +++-
 xen/include/asm-arm/domain.h     |   16 +-
 xen/include/asm-arm/event.h      |    3 +
 xen/include/asm-arm/gic.h        |    5 +-
 xen/include/asm-arm/gic_v3_its.h |   44 ++
 xen/include/asm-arm/vgic-emul.h  |    9 +
 xen/include/asm-arm/vgic.h       |   18 +-
 15 files changed, 2413 insertions(+), 82 deletions(-)

-- 
2.9.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* [PATCH v11 01/34] ARM: vGIC: avoid rank lock when reading priority
  2017-06-09 17:41 [PATCH v11 00/34] arm64: Dom0 ITS emulation Andre Przywara
@ 2017-06-09 17:41 ` Andre Przywara
  2017-06-12 14:49   ` Julien Grall
  2017-06-09 17:41 ` [PATCH v11 02/34] ARM: GICv3: enable ITS on the host Andre Przywara
                   ` (33 subsequent siblings)
  34 siblings, 1 reply; 71+ messages in thread
From: Andre Przywara @ 2017-06-09 17:41 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

When reading the priority value of a virtual interrupt, we were taking
the respective rank lock so far.
However for forwarded interrupts (Dom0 only so far) this may lead to a
deadlock with the following call chain:
- MMIO access to change the IRQ affinity, calling the ITARGETSR handler
- this handler takes the appropriate rank lock and calls vgic_store_itargetsr()
- vgic_store_itargetsr() will eventually call vgic_migrate_irq()
- if this IRQ is already in-flight, it will remove it from the old
  VCPU and inject it into the new one, by calling vgic_vcpu_inject_irq()
- vgic_vcpu_inject_irq will call vgic_get_virq_priority()
- vgic_get_virq_priority() tries to take the rank lock - again!
It seems like this code path has never been exercised before.

Fix this by avoiding taking the lock in vgic_get_virq_priority() (like we
do in vgic_get_target_vcpu()).
Actually we are just reading one byte, and priority changes while
interrupts are handled are a benign race that can happen on real hardware
too. So it is safe to just prevent the compiler from reading from the
struct more than once.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 xen/arch/arm/vgic-v2.c | 13 ++++++++-----
 xen/arch/arm/vgic-v3.c | 11 +++++++----
 xen/arch/arm/vgic.c    |  8 +-------
 3 files changed, 16 insertions(+), 16 deletions(-)

diff --git a/xen/arch/arm/vgic-v2.c b/xen/arch/arm/vgic-v2.c
index dc9f95b..5370020 100644
--- a/xen/arch/arm/vgic-v2.c
+++ b/xen/arch/arm/vgic-v2.c
@@ -258,9 +258,9 @@ static int vgic_v2_distr_mmio_read(struct vcpu *v, mmio_info_t *info,
         if ( rank == NULL ) goto read_as_zero;
 
         vgic_lock_rank(v, rank, flags);
-        ipriorityr = rank->ipriorityr[REG_RANK_INDEX(8,
-                                                     gicd_reg - GICD_IPRIORITYR,
-                                                     DABT_WORD)];
+        ipriorityr = ACCESS_ONCE(rank->ipriorityr[REG_RANK_INDEX(8,
+                                     gicd_reg - GICD_IPRIORITYR,
+                                     DABT_WORD)]);
         vgic_unlock_rank(v, rank, flags);
         *r = vgic_reg32_extract(ipriorityr, info);
 
@@ -499,7 +499,7 @@ static int vgic_v2_distr_mmio_write(struct vcpu *v, mmio_info_t *info,
 
     case VRANGE32(GICD_IPRIORITYR, GICD_IPRIORITYRN):
     {
-        uint32_t *ipriorityr;
+        uint32_t *ipriorityr, priority;
 
         if ( dabt.size != DABT_BYTE && dabt.size != DABT_WORD ) goto bad_width;
         rank = vgic_rank_offset(v, 8, gicd_reg - GICD_IPRIORITYR, DABT_WORD);
@@ -508,7 +508,10 @@ static int vgic_v2_distr_mmio_write(struct vcpu *v, mmio_info_t *info,
         ipriorityr = &rank->ipriorityr[REG_RANK_INDEX(8,
                                                       gicd_reg - GICD_IPRIORITYR,
                                                       DABT_WORD)];
-        vgic_reg32_update(ipriorityr, r, info);
+        priority = ACCESS_ONCE(*ipriorityr);
+        vgic_reg32_update(&priority, r, info);
+        ACCESS_ONCE(*ipriorityr) = priority;
+
         vgic_unlock_rank(v, rank, flags);
         return 1;
     }
diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
index d10757a..8abc069 100644
--- a/xen/arch/arm/vgic-v3.c
+++ b/xen/arch/arm/vgic-v3.c
@@ -521,8 +521,9 @@ static int __vgic_v3_distr_common_mmio_read(const char *name, struct vcpu *v,
         if ( rank == NULL ) goto read_as_zero;
 
         vgic_lock_rank(v, rank, flags);
-        ipriorityr = rank->ipriorityr[REG_RANK_INDEX(8, reg - GICD_IPRIORITYR,
-                                                     DABT_WORD)];
+        ipriorityr = ACCESS_ONCE(rank->ipriorityr[REG_RANK_INDEX(8,
+                                     reg - GICD_IPRIORITYR,
+                                     DABT_WORD)]);
         vgic_unlock_rank(v, rank, flags);
 
         *r = vgic_reg32_extract(ipriorityr, info);
@@ -630,7 +631,7 @@ static int __vgic_v3_distr_common_mmio_write(const char *name, struct vcpu *v,
 
     case VRANGE32(GICD_IPRIORITYR, GICD_IPRIORITYRN):
     {
-        uint32_t *ipriorityr;
+        uint32_t *ipriorityr, priority;
 
         if ( dabt.size != DABT_BYTE && dabt.size != DABT_WORD ) goto bad_width;
         rank = vgic_rank_offset(v, 8, reg - GICD_IPRIORITYR, DABT_WORD);
@@ -638,7 +639,9 @@ static int __vgic_v3_distr_common_mmio_write(const char *name, struct vcpu *v,
         vgic_lock_rank(v, rank, flags);
         ipriorityr = &rank->ipriorityr[REG_RANK_INDEX(8, reg - GICD_IPRIORITYR,
                                                       DABT_WORD)];
-        vgic_reg32_update(ipriorityr, r, info);
+        priority = ACCESS_ONCE(*ipriorityr);
+        vgic_reg32_update(&priority, r, info);
+        ACCESS_ONCE(*ipriorityr) = priority;
         vgic_unlock_rank(v, rank, flags);
         return 1;
     }
diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
index 83569b0..18fe420 100644
--- a/xen/arch/arm/vgic.c
+++ b/xen/arch/arm/vgic.c
@@ -227,14 +227,8 @@ struct vcpu *vgic_get_target_vcpu(struct vcpu *v, unsigned int virq)
 static int vgic_get_virq_priority(struct vcpu *v, unsigned int virq)
 {
     struct vgic_irq_rank *rank = vgic_rank_irq(v, virq);
-    unsigned long flags;
-    int priority;
-
-    vgic_lock_rank(v, rank, flags);
-    priority = rank->priority[virq & INTERRUPT_RANK_MASK];
-    vgic_unlock_rank(v, rank, flags);
 
-    return priority;
+    return ACCESS_ONCE(rank->priority[virq & INTERRUPT_RANK_MASK]);
 }
 
 bool vgic_migrate_irq(struct vcpu *old, struct vcpu *new, unsigned int irq)
-- 
2.9.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* [PATCH v11 02/34] ARM: GICv3: enable ITS on the host
  2017-06-09 17:41 [PATCH v11 00/34] arm64: Dom0 ITS emulation Andre Przywara
  2017-06-09 17:41 ` [PATCH v11 01/34] ARM: vGIC: avoid rank lock when reading priority Andre Przywara
@ 2017-06-09 17:41 ` Andre Przywara
  2017-06-12 14:51   ` Julien Grall
  2017-06-09 17:41 ` [PATCH v11 03/34] ARM: GICv3: enable LPIs " Andre Przywara
                   ` (32 subsequent siblings)
  34 siblings, 1 reply; 71+ messages in thread
From: Andre Przywara @ 2017-06-09 17:41 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

Even though the ITS emulation is not yet in place, the host ITS already
gets initialized and Xen tries to map the host collections.
However for commands to be processed we need to *enable* the ITS, which
will be done in a later patch not yet merged.
So those MAPC commands are not processed and run into a timeout, leading
to a panic on machines which advertise an ITS in their DT.
This patch just enables the ITS (but not the LPIs on each redistributor),
to get those MAPC commands executed.
This patch was part of: "ARM: GICv3: enable ITS and LPIs on the host"
(patch v8 06/27 or v10 12/32, which was already acked by Stefano.

This fixes booting Xen on ARM64 machines with an ITS and the
(EXPERT) ITS Kconfig option enabled.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 xen/arch/arm/gic-v3-its.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
index 07280b3..aebc257 100644
--- a/xen/arch/arm/gic-v3-its.c
+++ b/xen/arch/arm/gic-v3-its.c
@@ -505,6 +505,10 @@ static int gicv3_its_init_single_its(struct host_its *hw_its)
         return -ENOMEM;
     writeq_relaxed(0, hw_its->its_base + GITS_CWRITER);
 
+    /* Now enable interrupt translation and command processing on that ITS. */
+    reg = readl_relaxed(hw_its->its_base + GITS_CTLR);
+    writel_relaxed(reg | GITS_CTLR_ENABLE, hw_its->its_base + GITS_CTLR);
+
     return 0;
 }
 
-- 
2.9.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* [PATCH v11 03/34] ARM: GICv3: enable LPIs on the host
  2017-06-09 17:41 [PATCH v11 00/34] arm64: Dom0 ITS emulation Andre Przywara
  2017-06-09 17:41 ` [PATCH v11 01/34] ARM: vGIC: avoid rank lock when reading priority Andre Przywara
  2017-06-09 17:41 ` [PATCH v11 02/34] ARM: GICv3: enable ITS on the host Andre Przywara
@ 2017-06-09 17:41 ` Andre Przywara
  2017-06-09 17:41 ` [PATCH v11 04/34] ARM: GICv3: setup number of LPI bits for a GICv3 guest Andre Przywara
                   ` (31 subsequent siblings)
  34 siblings, 0 replies; 71+ messages in thread
From: Andre Przywara @ 2017-06-09 17:41 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

Now that the host part of the ITS code is in place, we can enable the
LPIs on each redistributor to get the show rolling.
At this point there would be no LPIs mapped, as guests don't know about
the ITS yet.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Acked-by: Stefano Stabellini <sstabellini@kernel.org>
---
 xen/arch/arm/gic-v3.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c
index a559e5e..eda3410 100644
--- a/xen/arch/arm/gic-v3.c
+++ b/xen/arch/arm/gic-v3.c
@@ -620,6 +620,21 @@ static int gicv3_enable_redist(void)
     return 0;
 }
 
+/* Enable LPIs on this redistributor (only useful when the host has an ITS). */
+static bool gicv3_enable_lpis(void)
+{
+    uint32_t val;
+
+    val = readl_relaxed(GICD_RDIST_BASE + GICR_TYPER);
+    if ( !(val & GICR_TYPER_PLPIS) )
+        return false;
+
+    val = readl_relaxed(GICD_RDIST_BASE + GICR_CTLR);
+    writel_relaxed(val | GICR_CTLR_ENABLE_LPIS, GICD_RDIST_BASE + GICR_CTLR);
+
+    return true;
+}
+
 static int __init gicv3_populate_rdist(void)
 {
     int i;
@@ -731,11 +746,14 @@ static int gicv3_cpu_init(void)
     if ( gicv3_enable_redist() )
         return -ENODEV;
 
+    /* If the host has any ITSes, enable LPIs now. */
     if ( gicv3_its_host_has_its() )
     {
         ret = gicv3_its_setup_collection(smp_processor_id());
         if ( ret )
             return ret;
+        if ( !gicv3_enable_lpis() )
+            return -EBUSY;
     }
 
     /* Set priority on PPI and SGI interrupts */
-- 
2.9.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* [PATCH v11 04/34] ARM: GICv3: setup number of LPI bits for a GICv3 guest
  2017-06-09 17:41 [PATCH v11 00/34] arm64: Dom0 ITS emulation Andre Przywara
                   ` (2 preceding siblings ...)
  2017-06-09 17:41 ` [PATCH v11 03/34] ARM: GICv3: enable LPIs " Andre Przywara
@ 2017-06-09 17:41 ` Andre Przywara
  2017-06-12 15:03   ` Julien Grall
  2017-06-09 17:41 ` [PATCH v11 05/34] ARM: vGIC: rework gic_remove_from_queues() Andre Przywara
                   ` (30 subsequent siblings)
  34 siblings, 1 reply; 71+ messages in thread
From: Andre Przywara @ 2017-06-09 17:41 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

The host supports a certain number of LPI identifiers, as stored in
the GICD_TYPER register.
Store this number from the hardware register in vgic_v3_hw to allow
injecting the very same number into a guest (Dom0).
DomUs get the legacy number of 10 bits here, since for now it only sees
SPIs, so it does not need more. This should be revisited once we get
proper DomU ITS support.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 xen/arch/arm/gic-v3.c        |  6 +++++-
 xen/arch/arm/vgic-v3.c       | 16 +++++++++++++++-
 xen/include/asm-arm/domain.h |  1 +
 xen/include/asm-arm/vgic.h   |  3 ++-
 4 files changed, 23 insertions(+), 3 deletions(-)

diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c
index eda3410..fc3614e 100644
--- a/xen/arch/arm/gic-v3.c
+++ b/xen/arch/arm/gic-v3.c
@@ -1597,6 +1597,7 @@ static int __init gicv3_init(void)
 {
     int res, i;
     uint32_t reg;
+    unsigned int intid_bits;
 
     if ( !cpu_has_gicv3 )
     {
@@ -1640,8 +1641,11 @@ static int __init gicv3_init(void)
                i, r->base, r->base + r->size);
     }
 
+    reg = readl_relaxed(GICD + GICD_TYPER);
+    intid_bits = GICD_TYPE_ID_BITS(reg);
+
     vgic_v3_setup_hw(dbase, gicv3.rdist_count, gicv3.rdist_regions,
-                     gicv3.rdist_stride);
+                     gicv3.rdist_stride, intid_bits);
     gicv3_init_v2();
 
     spin_lock_init(&gicv3.lock);
diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
index 8abc069..2b2b4e9 100644
--- a/xen/arch/arm/vgic-v3.c
+++ b/xen/arch/arm/vgic-v3.c
@@ -57,18 +57,21 @@ static struct {
     unsigned int nr_rdist_regions;
     const struct rdist_region *regions;
     uint32_t rdist_stride; /* Re-distributor stride */
+    unsigned int intid_bits;  /* Number of interrupt ID bits */
 } vgic_v3_hw;
 
 void vgic_v3_setup_hw(paddr_t dbase,
                       unsigned int nr_rdist_regions,
                       const struct rdist_region *regions,
-                      uint32_t rdist_stride)
+                      uint32_t rdist_stride,
+                      unsigned int intid_bits)
 {
     vgic_v3_hw.enabled = 1;
     vgic_v3_hw.dbase = dbase;
     vgic_v3_hw.nr_rdist_regions = nr_rdist_regions;
     vgic_v3_hw.regions = regions;
     vgic_v3_hw.rdist_stride = rdist_stride;
+    vgic_v3_hw.intid_bits = intid_bits;
 }
 
 static struct vcpu *vgic_v3_irouter_to_vcpu(struct domain *d, uint64_t irouter)
@@ -1485,6 +1488,8 @@ static int vgic_v3_domain_init(struct domain *d)
 
             first_cpu += size / d->arch.vgic.rdist_stride;
         }
+
+        d->arch.vgic.intid_bits = vgic_v3_hw.intid_bits;
     }
     else
     {
@@ -1500,6 +1505,15 @@ static int vgic_v3_domain_init(struct domain *d)
         d->arch.vgic.rdist_regions[0].base = GUEST_GICV3_GICR0_BASE;
         d->arch.vgic.rdist_regions[0].size = GUEST_GICV3_GICR0_SIZE;
         d->arch.vgic.rdist_regions[0].first_cpu = 0;
+
+        /*
+         * TODO: only SPIs for now, adjust this when guests need LPIs.
+         * Please note that this value just describes the bits required
+         * in the stream interface, which is of no real concern for our
+         * emulation. So we just go with "10" here to cover all eventual
+         * SPIs (even if the guest implements less).
+         */
+        d->arch.vgic.intid_bits = 10;
     }
 
     ret = vgic_v3_its_init_domain(d);
diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
index 6de8082..7c3829d 100644
--- a/xen/include/asm-arm/domain.h
+++ b/xen/include/asm-arm/domain.h
@@ -111,6 +111,7 @@ struct arch_domain
         uint32_t rdist_stride;              /* Re-Distributor stride */
         struct rb_root its_devices;         /* Devices mapped to an ITS */
         spinlock_t its_devices_lock;        /* Protects the its_devices tree */
+        unsigned int intid_bits;
 #endif
     } vgic;
 
diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h
index 544867a..df75064 100644
--- a/xen/include/asm-arm/vgic.h
+++ b/xen/include/asm-arm/vgic.h
@@ -346,7 +346,8 @@ struct rdist_region;
 void vgic_v3_setup_hw(paddr_t dbase,
                       unsigned int nr_rdist_regions,
                       const struct rdist_region *regions,
-                      uint32_t rdist_stride);
+                      uint32_t rdist_stride,
+                      unsigned int intid_bits);
 #endif
 
 #endif /* __ASM_ARM_VGIC_H__ */
-- 
2.9.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* [PATCH v11 05/34] ARM: vGIC: rework gic_remove_from_queues()
  2017-06-09 17:41 [PATCH v11 00/34] arm64: Dom0 ITS emulation Andre Przywara
                   ` (3 preceding siblings ...)
  2017-06-09 17:41 ` [PATCH v11 04/34] ARM: GICv3: setup number of LPI bits for a GICv3 guest Andre Przywara
@ 2017-06-09 17:41 ` Andre Przywara
  2017-06-12 15:15   ` Julien Grall
  2017-06-09 17:41 ` [PATCH v11 06/34] ARM: vGIC: move irq_to_pending() calls under the VGIC VCPU lock Andre Przywara
                   ` (29 subsequent siblings)
  34 siblings, 1 reply; 71+ messages in thread
From: Andre Przywara @ 2017-06-09 17:41 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

The function name gic_remove_from_queues() was a bit of a misnomer,
since it just removes an IRQ from the pending queue, not both queues.
Rename the function to make this more clear, also give it a pointer to
a struct pending_irq directly and rely on the VGIC VCPU lock to be
already taken, so this can be used in more places.
Replace the list removal in gic_clear_pending_irqs() with a call to
this function.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 xen/arch/arm/gic.c        | 12 ++++--------
 xen/arch/arm/vgic.c       |  5 ++++-
 xen/include/asm-arm/gic.h |  2 +-
 3 files changed, 9 insertions(+), 10 deletions(-)

diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index da19130..6c0c9c3 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -400,15 +400,11 @@ static inline void gic_add_to_lr_pending(struct vcpu *v, struct pending_irq *n)
     list_add_tail(&n->lr_queue, &v->arch.vgic.lr_pending);
 }
 
-void gic_remove_from_queues(struct vcpu *v, unsigned int virtual_irq)
+void gic_remove_from_lr_pending(struct vcpu *v, struct pending_irq *p)
 {
-    struct pending_irq *p = irq_to_pending(v, virtual_irq);
-    unsigned long flags;
+    ASSERT(spin_is_locked(&v->arch.vgic.lock));
 
-    spin_lock_irqsave(&v->arch.vgic.lock, flags);
-    if ( !list_empty(&p->lr_queue) )
-        list_del_init(&p->lr_queue);
-    spin_unlock_irqrestore(&v->arch.vgic.lock, flags);
+    list_del_init(&p->lr_queue);
 }
 
 void gic_raise_inflight_irq(struct vcpu *v, unsigned int virtual_irq)
@@ -609,7 +605,7 @@ void gic_clear_pending_irqs(struct vcpu *v)
 
     v->arch.lr_mask = 0;
     list_for_each_entry_safe ( p, t, &v->arch.vgic.lr_pending, lr_queue )
-        list_del_init(&p->lr_queue);
+        gic_remove_from_lr_pending(v, p);
 }
 
 int gic_events_need_delivery(void)
diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
index 18fe420..45926ab 100644
--- a/xen/arch/arm/vgic.c
+++ b/xen/arch/arm/vgic.c
@@ -307,9 +307,12 @@ void vgic_disable_irqs(struct vcpu *v, uint32_t r, int n)
     while ( (i = find_next_bit(&mask, 32, i)) < 32 ) {
         irq = i + (32 * n);
         v_target = vgic_get_target_vcpu(v, irq);
+        spin_lock_irqsave(&v_target->arch.vgic.lock, flags);
         p = irq_to_pending(v_target, irq);
         clear_bit(GIC_IRQ_GUEST_ENABLED, &p->status);
-        gic_remove_from_queues(v_target, irq);
+        gic_remove_from_lr_pending(v_target, p);
+        spin_unlock_irqrestore(&v_target->arch.vgic.lock, flags);
+
         if ( p->desc != NULL )
         {
             spin_lock_irqsave(&p->desc->lock, flags);
diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
index 836a103..3130634 100644
--- a/xen/include/asm-arm/gic.h
+++ b/xen/include/asm-arm/gic.h
@@ -243,7 +243,7 @@ extern void init_maintenance_interrupt(void);
 extern void gic_raise_guest_irq(struct vcpu *v, unsigned int irq,
         unsigned int priority);
 extern void gic_raise_inflight_irq(struct vcpu *v, unsigned int virtual_irq);
-extern void gic_remove_from_queues(struct vcpu *v, unsigned int virtual_irq);
+extern void gic_remove_from_lr_pending(struct vcpu *v, struct pending_irq *p);
 
 /* Accept an interrupt from the GIC and dispatch its handler */
 extern void gic_interrupt(struct cpu_user_regs *regs, int is_fiq);
-- 
2.9.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* [PATCH v11 06/34] ARM: vGIC: move irq_to_pending() calls under the VGIC VCPU lock
  2017-06-09 17:41 [PATCH v11 00/34] arm64: Dom0 ITS emulation Andre Przywara
                   ` (4 preceding siblings ...)
  2017-06-09 17:41 ` [PATCH v11 05/34] ARM: vGIC: rework gic_remove_from_queues() Andre Przywara
@ 2017-06-09 17:41 ` Andre Przywara
  2017-06-12 15:22   ` Julien Grall
  2017-06-09 17:41 ` [PATCH v11 07/34] ARM: vGIC: introduce gic_remove_irq() Andre Przywara
                   ` (28 subsequent siblings)
  34 siblings, 1 reply; 71+ messages in thread
From: Andre Przywara @ 2017-06-09 17:41 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

So far irq_to_pending() is just a convenience function to lookup
statically allocated arrays. This will change with LPIs, which are
more dynamic, so the memory for their struct pending_irq might go away.
The proper answer to the issue of preventing stale pointers is
ref-counting, which requires more rework and will be introduced with
a later rework.
For now move the irq_to_pending() calls that are used with LPIs under the
VGIC VCPU lock, and only use the returned pointer while holding the lock.
This prevents the memory from being freed while we use it.
For the sake of completeness we take care about all irq_to_pending()
users, even those which later will never deal with LPIs.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 xen/arch/arm/vgic.c | 40 +++++++++++++++++++++++++++++++---------
 1 file changed, 31 insertions(+), 9 deletions(-)

diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
index 45926ab..f2f423f 100644
--- a/xen/arch/arm/vgic.c
+++ b/xen/arch/arm/vgic.c
@@ -234,23 +234,29 @@ static int vgic_get_virq_priority(struct vcpu *v, unsigned int virq)
 bool vgic_migrate_irq(struct vcpu *old, struct vcpu *new, unsigned int irq)
 {
     unsigned long flags;
-    struct pending_irq *p = irq_to_pending(old, irq);
+    struct pending_irq *p;
+
+    spin_lock_irqsave(&old->arch.vgic.lock, flags);
+
+    p = irq_to_pending(old, irq);
 
     /* nothing to do for virtual interrupts */
     if ( p->desc == NULL )
+    {
+        spin_unlock_irqrestore(&old->arch.vgic.lock, flags);
         return true;
+    }
 
     /* migration already in progress, no need to do anything */
     if ( test_bit(GIC_IRQ_GUEST_MIGRATING, &p->status) )
     {
         gprintk(XENLOG_WARNING, "irq %u migration failed: requested while in progress\n", irq);
+        spin_unlock_irqrestore(&old->arch.vgic.lock, flags);
         return false;
     }
 
     perfc_incr(vgic_irq_migrates);
 
-    spin_lock_irqsave(&old->arch.vgic.lock, flags);
-
     if ( list_empty(&p->inflight) )
     {
         irq_set_affinity(p->desc, cpumask_of(new->processor));
@@ -285,6 +291,17 @@ void arch_move_irqs(struct vcpu *v)
     struct vcpu *v_target;
     int i;
 
+    /*
+     * We don't migrate LPIs at the moment.
+     * If we ever do, we must make sure that the struct pending_irq does
+     * not go away, as there is no lock preventing this here.
+     * To ensure this, we check if the loop below ever touches LPIs.
+     * In the moment vgic_num_irqs() just covers SPIs, as it's mostly used
+     * for allocating the pending_irq and irq_desc array, in which LPIs
+     * don't participate.
+     */
+    ASSERT(!is_lpi(vgic_num_irqs(d) - 1));
+
     for ( i = 32; i < vgic_num_irqs(d); i++ )
     {
         v_target = vgic_get_target_vcpu(v, i);
@@ -299,6 +316,7 @@ void vgic_disable_irqs(struct vcpu *v, uint32_t r, int n)
 {
     const unsigned long mask = r;
     struct pending_irq *p;
+    struct irq_desc *desc;
     unsigned int irq;
     unsigned long flags;
     int i = 0;
@@ -307,17 +325,19 @@ void vgic_disable_irqs(struct vcpu *v, uint32_t r, int n)
     while ( (i = find_next_bit(&mask, 32, i)) < 32 ) {
         irq = i + (32 * n);
         v_target = vgic_get_target_vcpu(v, irq);
+
         spin_lock_irqsave(&v_target->arch.vgic.lock, flags);
         p = irq_to_pending(v_target, irq);
         clear_bit(GIC_IRQ_GUEST_ENABLED, &p->status);
         gic_remove_from_lr_pending(v_target, p);
+        desc = p->desc;
         spin_unlock_irqrestore(&v_target->arch.vgic.lock, flags);
 
-        if ( p->desc != NULL )
+        if ( desc != NULL )
         {
-            spin_lock_irqsave(&p->desc->lock, flags);
-            p->desc->handler->disable(p->desc);
-            spin_unlock_irqrestore(&p->desc->lock, flags);
+            spin_lock_irqsave(&desc->lock, flags);
+            desc->handler->disable(desc);
+            spin_unlock_irqrestore(&desc->lock, flags);
         }
         i++;
     }
@@ -352,9 +372,9 @@ void vgic_enable_irqs(struct vcpu *v, uint32_t r, int n)
     while ( (i = find_next_bit(&mask, 32, i)) < 32 ) {
         irq = i + (32 * n);
         v_target = vgic_get_target_vcpu(v, irq);
+        spin_lock_irqsave(&v_target->arch.vgic.lock, flags);
         p = irq_to_pending(v_target, irq);
         set_bit(GIC_IRQ_GUEST_ENABLED, &p->status);
-        spin_lock_irqsave(&v_target->arch.vgic.lock, flags);
         if ( !list_empty(&p->inflight) && !test_bit(GIC_IRQ_GUEST_VISIBLE, &p->status) )
             gic_raise_guest_irq(v_target, irq, p->priority);
         spin_unlock_irqrestore(&v_target->arch.vgic.lock, flags);
@@ -463,7 +483,7 @@ void vgic_clear_pending_irqs(struct vcpu *v)
 void vgic_vcpu_inject_irq(struct vcpu *v, unsigned int virq)
 {
     uint8_t priority;
-    struct pending_irq *iter, *n = irq_to_pending(v, virq);
+    struct pending_irq *iter, *n;
     unsigned long flags;
     bool running;
 
@@ -471,6 +491,8 @@ void vgic_vcpu_inject_irq(struct vcpu *v, unsigned int virq)
 
     spin_lock_irqsave(&v->arch.vgic.lock, flags);
 
+    n = irq_to_pending(v, virq);
+
     /* vcpu offline */
     if ( test_bit(_VPF_down, &v->pause_flags) )
     {
-- 
2.9.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* [PATCH v11 07/34] ARM: vGIC: introduce gic_remove_irq()
  2017-06-09 17:41 [PATCH v11 00/34] arm64: Dom0 ITS emulation Andre Przywara
                   ` (5 preceding siblings ...)
  2017-06-09 17:41 ` [PATCH v11 06/34] ARM: vGIC: move irq_to_pending() calls under the VGIC VCPU lock Andre Przywara
@ 2017-06-09 17:41 ` Andre Przywara
  2017-06-12 15:28   ` Julien Grall
  2017-06-09 17:41 ` [PATCH v11 08/34] ARM: GIC: Add checks for NULL pointer pending_irq's Andre Przywara
                   ` (27 subsequent siblings)
  34 siblings, 1 reply; 71+ messages in thread
From: Andre Przywara @ 2017-06-09 17:41 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

To avoid code duplication in a later patch, introduce a generic function
to remove a virtual IRQ from the VGIC.
Call that function instead of the open-coded version in vgic_migrate_irq().

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 xen/arch/arm/gic.c        | 9 +++++++++
 xen/arch/arm/vgic.c       | 4 +---
 xen/include/asm-arm/gic.h | 1 +
 3 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index 6c0c9c3..e0c54d5 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -407,6 +407,15 @@ void gic_remove_from_lr_pending(struct vcpu *v, struct pending_irq *p)
     list_del_init(&p->lr_queue);
 }
 
+void gic_remove_irq(struct vcpu *v, struct pending_irq *p)
+{
+    ASSERT(spin_is_locked(&v->arch.vgic.lock));
+
+    clear_bit(GIC_IRQ_GUEST_QUEUED, &p->status);
+    list_del_init(&p->inflight);
+    gic_remove_from_lr_pending(v, p);
+}
+
 void gic_raise_inflight_irq(struct vcpu *v, unsigned int virtual_irq)
 {
     struct pending_irq *n = irq_to_pending(v, virtual_irq);
diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
index f2f423f..f0d288d 100644
--- a/xen/arch/arm/vgic.c
+++ b/xen/arch/arm/vgic.c
@@ -266,9 +266,7 @@ bool vgic_migrate_irq(struct vcpu *old, struct vcpu *new, unsigned int irq)
     /* If the IRQ is still lr_pending, re-inject it to the new vcpu */
     if ( !list_empty(&p->lr_queue) )
     {
-        clear_bit(GIC_IRQ_GUEST_QUEUED, &p->status);
-        list_del_init(&p->lr_queue);
-        list_del_init(&p->inflight);
+        gic_remove_irq(old, p);
         irq_set_affinity(p->desc, cpumask_of(new->processor));
         spin_unlock_irqrestore(&old->arch.vgic.lock, flags);
         vgic_vcpu_inject_irq(new, irq);
diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
index 3130634..5d5b4cc 100644
--- a/xen/include/asm-arm/gic.h
+++ b/xen/include/asm-arm/gic.h
@@ -244,6 +244,7 @@ extern void gic_raise_guest_irq(struct vcpu *v, unsigned int irq,
         unsigned int priority);
 extern void gic_raise_inflight_irq(struct vcpu *v, unsigned int virtual_irq);
 extern void gic_remove_from_lr_pending(struct vcpu *v, struct pending_irq *p);
+extern void gic_remove_irq(struct vcpu *v, struct pending_irq *p);
 
 /* Accept an interrupt from the GIC and dispatch its handler */
 extern void gic_interrupt(struct cpu_user_regs *regs, int is_fiq);
-- 
2.9.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* [PATCH v11 08/34] ARM: GIC: Add checks for NULL pointer pending_irq's
  2017-06-09 17:41 [PATCH v11 00/34] arm64: Dom0 ITS emulation Andre Przywara
                   ` (6 preceding siblings ...)
  2017-06-09 17:41 ` [PATCH v11 07/34] ARM: vGIC: introduce gic_remove_irq() Andre Przywara
@ 2017-06-09 17:41 ` Andre Przywara
  2017-06-12 15:30   ` Julien Grall
  2017-06-12 22:44   ` Stefano Stabellini
  2017-06-09 17:41 ` [PATCH v11 09/34] ARM: GICv3: introduce separate pending_irq structs for LPIs Andre Przywara
                   ` (26 subsequent siblings)
  34 siblings, 2 replies; 71+ messages in thread
From: Andre Przywara @ 2017-06-09 17:41 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

For LPIs the struct pending_irq's are dynamically allocated and the
pointers will be stored in a radix tree. Since an LPI can be "unmapped"
at any time, teach the VGIC how to deal with irq_to_pending() returning
a NULL pointer.
We just do nothing in this case or clean up the LR if the virtual LPI
number was still in an LR.

Those are all call sites for irq_to_pending(), as per:
"git grep irq_to_pending", and their evaluations:
(PROTECTED means: added NULL check and bailing out)

    xen/arch/arm/gic.c:
gic_route_irq_to_guest(): only called for SPIs, added ASSERT()
gic_remove_irq_from_guest(): only called for SPIs, added ASSERT()
gic_remove_from_lr_pending(): PROTECTED, called within VCPU VGIC lock
gic_raise_inflight_irq(): PROTECTED, called under VCPU VGIC lock
gic_raise_guest_irq(): PROTECTED, called under VCPU VGIC lock
gic_update_one_lr(): PROTECTED, called under VCPU VGIC lock

    xen/arch/arm/vgic.c:
vgic_migrate_irq(): not called for LPIs (virtual IRQs), added ASSERT()
arch_move_irqs(): not iterating over LPIs, LPI ASSERT already in place
vgic_disable_irqs(): not called for LPIs, added ASSERT()
vgic_enable_irqs(): not called for LPIs, added ASSERT()
vgic_vcpu_inject_irq(): PROTECTED, moved under VCPU VGIC lock

    xen/include/asm-arm/event.h:
local_events_need_delivery_nomask(): only called for a PPI, added ASSERT()

    xen/include/asm-arm/vgic.h:
(prototype)

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 xen/arch/arm/gic.c          | 26 ++++++++++++++++++++++++--
 xen/arch/arm/vgic.c         | 21 +++++++++++++++++++++
 xen/include/asm-arm/event.h |  3 +++
 3 files changed, 48 insertions(+), 2 deletions(-)

diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index e0c54d5..36e340b 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -148,6 +148,7 @@ int gic_route_irq_to_guest(struct domain *d, unsigned int virq,
     /* Caller has already checked that the IRQ is an SPI */
     ASSERT(virq >= 32);
     ASSERT(virq < vgic_num_irqs(d));
+    ASSERT(!is_lpi(virq));
 
     vgic_lock_rank(v_target, rank, flags);
 
@@ -184,6 +185,7 @@ int gic_remove_irq_from_guest(struct domain *d, unsigned int virq,
     ASSERT(spin_is_locked(&desc->lock));
     ASSERT(test_bit(_IRQ_GUEST, &desc->status));
     ASSERT(p->desc == desc);
+    ASSERT(!is_lpi(virq));
 
     vgic_lock_rank(v_target, rank, flags);
 
@@ -420,6 +422,10 @@ void gic_raise_inflight_irq(struct vcpu *v, unsigned int virtual_irq)
 {
     struct pending_irq *n = irq_to_pending(v, virtual_irq);
 
+    /* If an LPI has been removed meanwhile, there is nothing left to raise. */
+    if ( unlikely(!n) )
+        return;
+
     ASSERT(spin_is_locked(&v->arch.vgic.lock));
 
     if ( list_empty(&n->lr_queue) )
@@ -439,20 +445,25 @@ void gic_raise_guest_irq(struct vcpu *v, unsigned int virtual_irq,
 {
     int i;
     unsigned int nr_lrs = gic_hw_ops->info->nr_lrs;
+    struct pending_irq *p = irq_to_pending(v, virtual_irq);
 
     ASSERT(spin_is_locked(&v->arch.vgic.lock));
 
+    if ( unlikely(!p) )
+        /* An unmapped LPI does not need to be raised. */
+        return;
+
     if ( v == current && list_empty(&v->arch.vgic.lr_pending) )
     {
         i = find_first_zero_bit(&this_cpu(lr_mask), nr_lrs);
         if (i < nr_lrs) {
             set_bit(i, &this_cpu(lr_mask));
-            gic_set_lr(i, irq_to_pending(v, virtual_irq), GICH_LR_PENDING);
+            gic_set_lr(i, p, GICH_LR_PENDING);
             return;
         }
     }
 
-    gic_add_to_lr_pending(v, irq_to_pending(v, virtual_irq));
+    gic_add_to_lr_pending(v, p);
 }
 
 static void gic_update_one_lr(struct vcpu *v, int i)
@@ -467,6 +478,17 @@ static void gic_update_one_lr(struct vcpu *v, int i)
     gic_hw_ops->read_lr(i, &lr_val);
     irq = lr_val.virq;
     p = irq_to_pending(v, irq);
+    /* An LPI might have been unmapped, in which case we just clean up here. */
+    if ( unlikely(!p) )
+    {
+        ASSERT(is_lpi(irq));
+
+        gic_hw_ops->clear_lr(i);
+        clear_bit(i, &this_cpu(lr_mask));
+
+        return;
+    }
+
     if ( lr_val.state & GICH_LR_ACTIVE )
     {
         set_bit(GIC_IRQ_GUEST_ACTIVE, &p->status);
diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
index f0d288d..1edf93d 100644
--- a/xen/arch/arm/vgic.c
+++ b/xen/arch/arm/vgic.c
@@ -236,6 +236,9 @@ bool vgic_migrate_irq(struct vcpu *old, struct vcpu *new, unsigned int irq)
     unsigned long flags;
     struct pending_irq *p;
 
+    /* This will never be called for an LPI, as we don't migrate them. */
+    ASSERT(!is_lpi(irq));
+
     spin_lock_irqsave(&old->arch.vgic.lock, flags);
 
     p = irq_to_pending(old, irq);
@@ -320,6 +323,9 @@ void vgic_disable_irqs(struct vcpu *v, uint32_t r, int n)
     int i = 0;
     struct vcpu *v_target;
 
+    /* LPIs will never be disabled via this function. */
+    ASSERT(!is_lpi(32 * n + 31));
+
     while ( (i = find_next_bit(&mask, 32, i)) < 32 ) {
         irq = i + (32 * n);
         v_target = vgic_get_target_vcpu(v, irq);
@@ -367,6 +373,9 @@ void vgic_enable_irqs(struct vcpu *v, uint32_t r, int n)
     struct vcpu *v_target;
     struct domain *d = v->domain;
 
+    /* LPIs will never be enabled via this function. */
+    ASSERT(!is_lpi(32 * n + 31));
+
     while ( (i = find_next_bit(&mask, 32, i)) < 32 ) {
         irq = i + (32 * n);
         v_target = vgic_get_target_vcpu(v, irq);
@@ -447,6 +456,12 @@ bool vgic_to_sgi(struct vcpu *v, register_t sgir, enum gic_sgi_mode irqmode,
     return true;
 }
 
+/*
+ * Returns the pointer to the struct pending_irq belonging to the given
+ * interrupt.
+ * This can return NULL if called for an LPI which has been unmapped
+ * meanwhile.
+ */
 struct pending_irq *irq_to_pending(struct vcpu *v, unsigned int irq)
 {
     struct pending_irq *n;
@@ -490,6 +505,12 @@ void vgic_vcpu_inject_irq(struct vcpu *v, unsigned int virq)
     spin_lock_irqsave(&v->arch.vgic.lock, flags);
 
     n = irq_to_pending(v, virq);
+    /* If an LPI has been removed, there is nothing to inject here. */
+    if ( unlikely(!n) )
+    {
+        spin_unlock_irqrestore(&v->arch.vgic.lock, flags);
+        return;
+    }
 
     /* vcpu offline */
     if ( test_bit(_VPF_down, &v->pause_flags) )
diff --git a/xen/include/asm-arm/event.h b/xen/include/asm-arm/event.h
index 5330dfe..caefa50 100644
--- a/xen/include/asm-arm/event.h
+++ b/xen/include/asm-arm/event.h
@@ -19,6 +19,9 @@ static inline int local_events_need_delivery_nomask(void)
     struct pending_irq *p = irq_to_pending(current,
                                            current->domain->arch.evtchn_irq);
 
+    /* Does not work for LPIs. */
+    ASSERT(!is_lpi(current->domain->arch.evtchn_irq));
+
     /* XXX: if the first interrupt has already been delivered, we should
      * check whether any other interrupts with priority higher than the
      * one in GICV_IAR are in the lr_pending queue or in the LR
-- 
2.9.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* [PATCH v11 09/34] ARM: GICv3: introduce separate pending_irq structs for LPIs
  2017-06-09 17:41 [PATCH v11 00/34] arm64: Dom0 ITS emulation Andre Przywara
                   ` (7 preceding siblings ...)
  2017-06-09 17:41 ` [PATCH v11 08/34] ARM: GIC: Add checks for NULL pointer pending_irq's Andre Przywara
@ 2017-06-09 17:41 ` Andre Przywara
  2017-06-09 17:41 ` [PATCH v11 10/34] ARM: GIC: export and extend vgic_init_pending_irq() Andre Przywara
                   ` (25 subsequent siblings)
  34 siblings, 0 replies; 71+ messages in thread
From: Andre Przywara @ 2017-06-09 17:41 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

For the same reason that allocating a struct irq_desc for each
possible LPI is not an option, having a struct pending_irq for each LPI
is also not feasible. We only care about mapped LPIs, so we can get away
with having struct pending_irq's only for them.
Maintain a radix tree per domain where we drop the pointer to the
respective pending_irq. The index used is the virtual LPI number.
The memory for the actual structures has been allocated already per
device at device mapping time.
Teach the existing VGIC functions to find the right pointer when being
given a virtual LPI number.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Acked-by: Julien Grall <julien.grall@arm.com>
Reviewed-by: Stefano Stabellini <sstabellini@kernel.org>
---
 xen/arch/arm/vgic-v2.c       |  8 ++++++++
 xen/arch/arm/vgic-v3.c       | 30 ++++++++++++++++++++++++++++++
 xen/arch/arm/vgic.c          |  2 ++
 xen/include/asm-arm/domain.h |  2 ++
 xen/include/asm-arm/vgic.h   |  2 ++
 5 files changed, 44 insertions(+)

diff --git a/xen/arch/arm/vgic-v2.c b/xen/arch/arm/vgic-v2.c
index 5370020..ce2b96f 100644
--- a/xen/arch/arm/vgic-v2.c
+++ b/xen/arch/arm/vgic-v2.c
@@ -705,10 +705,18 @@ static void vgic_v2_domain_free(struct domain *d)
     /* Nothing to be cleanup for this driver */
 }
 
+static struct pending_irq *vgic_v2_lpi_to_pending(struct domain *d,
+                                                  unsigned int vlpi)
+{
+    /* Dummy function, no LPIs on a VGICv2. */
+    BUG();
+}
+
 static const struct vgic_ops vgic_v2_ops = {
     .vcpu_init   = vgic_v2_vcpu_init,
     .domain_init = vgic_v2_domain_init,
     .domain_free = vgic_v2_domain_free,
+    .lpi_to_pending = vgic_v2_lpi_to_pending,
     .max_vcpus = 8,
 };
 
diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
index 2b2b4e9..e116ae7 100644
--- a/xen/arch/arm/vgic-v3.c
+++ b/xen/arch/arm/vgic-v3.c
@@ -1457,6 +1457,9 @@ static int vgic_v3_domain_init(struct domain *d)
     d->arch.vgic.nr_regions = rdist_count;
     d->arch.vgic.rdist_regions = rdist_regions;
 
+    rwlock_init(&d->arch.vgic.pend_lpi_tree_lock);
+    radix_tree_init(&d->arch.vgic.pend_lpi_tree);
+
     /*
      * Domain 0 gets the hardware address.
      * Guests get the virtual platform layout.
@@ -1545,14 +1548,41 @@ static int vgic_v3_domain_init(struct domain *d)
 static void vgic_v3_domain_free(struct domain *d)
 {
     vgic_v3_its_free_domain(d);
+    /*
+     * It is expected that at this point all actual ITS devices have been
+     * cleaned up already. The struct pending_irq's, for which the pointers
+     * have been stored in the radix tree, are allocated and freed by device.
+     * On device unmapping all the entries are removed from the tree and
+     * the backing memory is freed.
+     */
+    radix_tree_destroy(&d->arch.vgic.pend_lpi_tree, NULL);
     xfree(d->arch.vgic.rdist_regions);
 }
 
+/*
+ * Looks up a virtual LPI number in our tree of mapped LPIs. This will return
+ * the corresponding struct pending_irq, which we also use to store the
+ * enabled and pending bit plus the priority.
+ * Returns NULL if an LPI cannot be found (or no LPIs are supported).
+ */
+static struct pending_irq *vgic_v3_lpi_to_pending(struct domain *d,
+                                                  unsigned int lpi)
+{
+    struct pending_irq *pirq;
+
+    read_lock(&d->arch.vgic.pend_lpi_tree_lock);
+    pirq = radix_tree_lookup(&d->arch.vgic.pend_lpi_tree, lpi);
+    read_unlock(&d->arch.vgic.pend_lpi_tree_lock);
+
+    return pirq;
+}
+
 static const struct vgic_ops v3_ops = {
     .vcpu_init   = vgic_v3_vcpu_init,
     .domain_init = vgic_v3_domain_init,
     .domain_free = vgic_v3_domain_free,
     .emulate_reg  = vgic_v3_emulate_reg,
+    .lpi_to_pending = vgic_v3_lpi_to_pending,
     /*
      * We use both AFF1 and AFF0 in (v)MPIDR. Thus, the max number of CPU
      * that can be supported is up to 4096(==256*16) in theory.
diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
index 1edf93d..2e4820f 100644
--- a/xen/arch/arm/vgic.c
+++ b/xen/arch/arm/vgic.c
@@ -469,6 +469,8 @@ struct pending_irq *irq_to_pending(struct vcpu *v, unsigned int irq)
      * are used for SPIs; the rests are used for per cpu irqs */
     if ( irq < 32 )
         n = &v->arch.vgic.pending_irqs[irq];
+    else if ( is_lpi(irq) )
+        n = v->domain->arch.vgic.handler->lpi_to_pending(v->domain, irq);
     else
         n = &v->domain->arch.vgic.pending_irqs[irq - 32];
     return n;
diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
index 7c3829d..3d8e84c 100644
--- a/xen/include/asm-arm/domain.h
+++ b/xen/include/asm-arm/domain.h
@@ -111,6 +111,8 @@ struct arch_domain
         uint32_t rdist_stride;              /* Re-Distributor stride */
         struct rb_root its_devices;         /* Devices mapped to an ITS */
         spinlock_t its_devices_lock;        /* Protects the its_devices tree */
+        struct radix_tree_root pend_lpi_tree; /* Stores struct pending_irq's */
+        rwlock_t pend_lpi_tree_lock;        /* Protects the pend_lpi_tree */
         unsigned int intid_bits;
 #endif
     } vgic;
diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h
index df75064..c9075a9 100644
--- a/xen/include/asm-arm/vgic.h
+++ b/xen/include/asm-arm/vgic.h
@@ -134,6 +134,8 @@ struct vgic_ops {
     void (*domain_free)(struct domain *d);
     /* vGIC sysreg/cpregs emulate */
     bool (*emulate_reg)(struct cpu_user_regs *regs, union hsr hsr);
+    /* lookup the struct pending_irq for a given LPI interrupt */
+    struct pending_irq *(*lpi_to_pending)(struct domain *d, unsigned int vlpi);
     /* Maximum number of vCPU supported */
     const unsigned int max_vcpus;
 };
-- 
2.9.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* [PATCH v11 10/34] ARM: GIC: export and extend vgic_init_pending_irq()
  2017-06-09 17:41 [PATCH v11 00/34] arm64: Dom0 ITS emulation Andre Przywara
                   ` (8 preceding siblings ...)
  2017-06-09 17:41 ` [PATCH v11 09/34] ARM: GICv3: introduce separate pending_irq structs for LPIs Andre Przywara
@ 2017-06-09 17:41 ` Andre Przywara
  2017-06-12 15:36   ` Julien Grall
  2017-06-09 17:41 ` [PATCH v11 11/34] ARM: vGIC: cache virtual LPI priority in struct pending_irq Andre Przywara
                   ` (24 subsequent siblings)
  34 siblings, 1 reply; 71+ messages in thread
From: Andre Przywara @ 2017-06-09 17:41 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

For LPIs we later want to dynamically allocate struct pending_irqs.
So beside needing to initialize the struct from there we also need
to clean it up and re-initialize it later on.
Export vgic_init_pending_irq() and extend it to be reusable.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 xen/arch/arm/vgic.c        | 4 +++-
 xen/include/asm-arm/vgic.h | 1 +
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
index 2e4820f..7e8dba6 100644
--- a/xen/arch/arm/vgic.c
+++ b/xen/arch/arm/vgic.c
@@ -60,8 +60,10 @@ struct vgic_irq_rank *vgic_rank_irq(struct vcpu *v, unsigned int irq)
     return vgic_get_rank(v, rank);
 }
 
-static void vgic_init_pending_irq(struct pending_irq *p, unsigned int virq)
+void vgic_init_pending_irq(struct pending_irq *p, unsigned int virq)
 {
+    memset(p, 0, sizeof(*p));
+
     INIT_LIST_HEAD(&p->inflight);
     INIT_LIST_HEAD(&p->lr_queue);
     p->irq = virq;
diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h
index c9075a9..a59be6d 100644
--- a/xen/include/asm-arm/vgic.h
+++ b/xen/include/asm-arm/vgic.h
@@ -300,6 +300,7 @@ extern struct vcpu *vgic_get_target_vcpu(struct vcpu *v, unsigned int virq);
 extern void vgic_vcpu_inject_irq(struct vcpu *v, unsigned int virq);
 extern void vgic_vcpu_inject_spi(struct domain *d, unsigned int virq);
 extern void vgic_clear_pending_irqs(struct vcpu *v);
+extern void vgic_init_pending_irq(struct pending_irq *p, unsigned int virq);
 extern struct pending_irq *irq_to_pending(struct vcpu *v, unsigned int irq);
 extern struct pending_irq *spi_to_pending(struct domain *d, unsigned int irq);
 extern struct vgic_irq_rank *vgic_rank_offset(struct vcpu *v, int b, int n, int s);
-- 
2.9.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* [PATCH v11 11/34] ARM: vGIC: cache virtual LPI priority in struct pending_irq
  2017-06-09 17:41 [PATCH v11 00/34] arm64: Dom0 ITS emulation Andre Przywara
                   ` (9 preceding siblings ...)
  2017-06-09 17:41 ` [PATCH v11 10/34] ARM: GIC: export and extend vgic_init_pending_irq() Andre Przywara
@ 2017-06-09 17:41 ` Andre Przywara
  2017-06-12 15:39   ` Julien Grall
  2017-06-09 17:41 ` [PATCH v11 12/34] ARM: vGIC: add LPI VCPU ID to " Andre Przywara
                   ` (23 subsequent siblings)
  34 siblings, 1 reply; 71+ messages in thread
From: Andre Przywara @ 2017-06-09 17:41 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

We enhance struct pending_irq to cache the priority information
for LPIs. Reading the information from there is faster than accessing
the property table from guest memory. Also it use some padding area in
the struct, so does not require more memory.
This introduces the function to retrieve the LPI priority as a vgic_ops.
Also this moves the vgic_get_virq_priority() call in
vgic_vcpu_inject_irq() to happen after the NULL check of the pending_irq
pointer, so we can rely on the pointer in the new function.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 xen/arch/arm/vgic-v2.c     |  7 +++++++
 xen/arch/arm/vgic-v3.c     | 11 +++++++++++
 xen/arch/arm/vgic.c        | 10 +++++++---
 xen/include/asm-arm/vgic.h |  2 ++
 4 files changed, 27 insertions(+), 3 deletions(-)

diff --git a/xen/arch/arm/vgic-v2.c b/xen/arch/arm/vgic-v2.c
index ce2b96f..327818d 100644
--- a/xen/arch/arm/vgic-v2.c
+++ b/xen/arch/arm/vgic-v2.c
@@ -712,11 +712,18 @@ static struct pending_irq *vgic_v2_lpi_to_pending(struct domain *d,
     BUG();
 }
 
+static int vgic_v2_lpi_get_priority(struct domain *d, unsigned int vlpi)
+{
+    /* Dummy function, no LPIs on a VGICv2. */
+    BUG();
+}
+
 static const struct vgic_ops vgic_v2_ops = {
     .vcpu_init   = vgic_v2_vcpu_init,
     .domain_init = vgic_v2_domain_init,
     .domain_free = vgic_v2_domain_free,
     .lpi_to_pending = vgic_v2_lpi_to_pending,
+    .lpi_get_priority = vgic_v2_lpi_get_priority,
     .max_vcpus = 8,
 };
 
diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
index e116ae7..66a758c 100644
--- a/xen/arch/arm/vgic-v3.c
+++ b/xen/arch/arm/vgic-v3.c
@@ -1577,12 +1577,23 @@ static struct pending_irq *vgic_v3_lpi_to_pending(struct domain *d,
     return pirq;
 }
 
+/* Retrieve the priority of an LPI from its struct pending_irq. */
+static int vgic_v3_lpi_get_priority(struct domain *d, uint32_t vlpi)
+{
+    struct pending_irq *p = vgic_v3_lpi_to_pending(d, vlpi);
+
+    ASSERT(p);
+
+    return p->lpi_priority;
+}
+
 static const struct vgic_ops v3_ops = {
     .vcpu_init   = vgic_v3_vcpu_init,
     .domain_init = vgic_v3_domain_init,
     .domain_free = vgic_v3_domain_free,
     .emulate_reg  = vgic_v3_emulate_reg,
     .lpi_to_pending = vgic_v3_lpi_to_pending,
+    .lpi_get_priority = vgic_v3_lpi_get_priority,
     /*
      * We use both AFF1 and AFF0 in (v)MPIDR. Thus, the max number of CPU
      * that can be supported is up to 4096(==256*16) in theory.
diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
index 7e8dba6..6f88616 100644
--- a/xen/arch/arm/vgic.c
+++ b/xen/arch/arm/vgic.c
@@ -228,8 +228,13 @@ struct vcpu *vgic_get_target_vcpu(struct vcpu *v, unsigned int virq)
 
 static int vgic_get_virq_priority(struct vcpu *v, unsigned int virq)
 {
-    struct vgic_irq_rank *rank = vgic_rank_irq(v, virq);
+    struct vgic_irq_rank *rank;
+
+    /* LPIs don't have a rank, also store their priority separately. */
+    if ( is_lpi(virq) )
+        return v->domain->arch.vgic.handler->lpi_get_priority(v->domain, virq);
 
+    rank = vgic_rank_irq(v, virq);
     return ACCESS_ONCE(rank->priority[virq & INTERRUPT_RANK_MASK]);
 }
 
@@ -504,8 +509,6 @@ void vgic_vcpu_inject_irq(struct vcpu *v, unsigned int virq)
     unsigned long flags;
     bool running;
 
-    priority = vgic_get_virq_priority(v, virq);
-
     spin_lock_irqsave(&v->arch.vgic.lock, flags);
 
     n = irq_to_pending(v, virq);
@@ -531,6 +534,7 @@ void vgic_vcpu_inject_irq(struct vcpu *v, unsigned int virq)
         goto out;
     }
 
+    priority = vgic_get_virq_priority(v, virq);
     n->priority = priority;
 
     /* the irq is enabled */
diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h
index a59be6d..d51e277 100644
--- a/xen/include/asm-arm/vgic.h
+++ b/xen/include/asm-arm/vgic.h
@@ -72,6 +72,7 @@ struct pending_irq
 #define GIC_INVALID_LR         (uint8_t)~0
     uint8_t lr;
     uint8_t priority;
+    uint8_t lpi_priority;       /* Caches the priority if this is an LPI. */
     /* inflight is used to append instances of pending_irq to
      * vgic.inflight_irqs */
     struct list_head inflight;
@@ -136,6 +137,7 @@ struct vgic_ops {
     bool (*emulate_reg)(struct cpu_user_regs *regs, union hsr hsr);
     /* lookup the struct pending_irq for a given LPI interrupt */
     struct pending_irq *(*lpi_to_pending)(struct domain *d, unsigned int vlpi);
+    int (*lpi_get_priority)(struct domain *d, uint32_t vlpi);
     /* Maximum number of vCPU supported */
     const unsigned int max_vcpus;
 };
-- 
2.9.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* [PATCH v11 12/34] ARM: vGIC: add LPI VCPU ID to struct pending_irq
  2017-06-09 17:41 [PATCH v11 00/34] arm64: Dom0 ITS emulation Andre Przywara
                   ` (10 preceding siblings ...)
  2017-06-09 17:41 ` [PATCH v11 11/34] ARM: vGIC: cache virtual LPI priority in struct pending_irq Andre Przywara
@ 2017-06-09 17:41 ` Andre Przywara
  2017-06-12 15:46   ` Julien Grall
  2017-06-09 17:41 ` [PATCH v11 13/34] ARM: GIC: ITS: remove no longer needed VCPU ID in host LPI entry Andre Przywara
                   ` (22 subsequent siblings)
  34 siblings, 1 reply; 71+ messages in thread
From: Andre Przywara @ 2017-06-09 17:41 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

The target CPU for an LPI is encoded in the interrupt translation table
entry, so can't be easily derived from just an LPI number (short of
walking *all* tables and find the matching LPI).
To avoid this in case we need to know the VCPU (for the INVALL command,
for instance), put the VCPU ID in the struct pending_irq, so that it is
easily accessible.
We use the remaining 8 bits of padding space for that to avoid enlarging
the size of struct pending_irq. The number of VCPUs is limited to 127
at the moment anyway, which we also confirm with a BUILD_BUG_ON.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 xen/arch/arm/vgic.c        | 4 ++++
 xen/include/asm-arm/vgic.h | 1 +
 2 files changed, 5 insertions(+)

diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
index 6f88616..546f412 100644
--- a/xen/arch/arm/vgic.c
+++ b/xen/arch/arm/vgic.c
@@ -62,11 +62,15 @@ struct vgic_irq_rank *vgic_rank_irq(struct vcpu *v, unsigned int irq)
 
 void vgic_init_pending_irq(struct pending_irq *p, unsigned int virq)
 {
+    /* The lpi_vcpu_id field must be big enough to hold a VCPU ID. */
+    BUILD_BUG_ON(BIT(sizeof(p->lpi_vcpu_id) * 8) < MAX_VIRT_CPUS);
+
     memset(p, 0, sizeof(*p));
 
     INIT_LIST_HEAD(&p->inflight);
     INIT_LIST_HEAD(&p->lr_queue);
     p->irq = virq;
+    p->lpi_vcpu_id = INVALID_VCPU_ID;
 }
 
 static void vgic_rank_init(struct vgic_irq_rank *rank, uint8_t index,
diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h
index d51e277..07b56dc 100644
--- a/xen/include/asm-arm/vgic.h
+++ b/xen/include/asm-arm/vgic.h
@@ -73,6 +73,7 @@ struct pending_irq
     uint8_t lr;
     uint8_t priority;
     uint8_t lpi_priority;       /* Caches the priority if this is an LPI. */
+    uint8_t lpi_vcpu_id;        /* The VCPU for an LPI. */
     /* inflight is used to append instances of pending_irq to
      * vgic.inflight_irqs */
     struct list_head inflight;
-- 
2.9.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* [PATCH v11 13/34] ARM: GIC: ITS: remove no longer needed VCPU ID in host LPI entry
  2017-06-09 17:41 [PATCH v11 00/34] arm64: Dom0 ITS emulation Andre Przywara
                   ` (11 preceding siblings ...)
  2017-06-09 17:41 ` [PATCH v11 12/34] ARM: vGIC: add LPI VCPU ID to " Andre Przywara
@ 2017-06-09 17:41 ` Andre Przywara
  2017-06-12 15:47   ` Julien Grall
  2017-06-09 17:41 ` [PATCH v11 14/34] ARM: GICv3: forward pending LPIs to guests Andre Przywara
                   ` (21 subsequent siblings)
  34 siblings, 1 reply; 71+ messages in thread
From: Andre Przywara @ 2017-06-09 17:41 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

To get easy access to the VCPU a forwareded LPI interrupt should be
injected to, so far we stored the VCPU ID in the host LPI entry.
However this creates a redundancy, since we keep the target VCPU in
the struct pending_irq already, which we can easily look up given the
domain and the virtual LPI number.
Apart from removing the redundancy this avoids having to update this
information later and keeping it in sync in a race-free fashion.
Since this information has not been used that, this patch actually does
not change anything, it just removes the declaration and initialization.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 xen/arch/arm/gic-v3-lpi.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/xen/arch/arm/gic-v3-lpi.c b/xen/arch/arm/gic-v3-lpi.c
index 292f2d0..dbaf45a 100644
--- a/xen/arch/arm/gic-v3-lpi.c
+++ b/xen/arch/arm/gic-v3-lpi.c
@@ -47,7 +47,7 @@ union host_lpi {
     struct {
         uint32_t virt_lpi;
         uint16_t dom_id;
-        uint16_t vcpu_id;
+        uint16_t pad;
     };
 };
 
@@ -417,7 +417,6 @@ int gicv3_allocate_host_lpi_block(struct domain *d, uint32_t *first_lpi)
          */
         hlpi.virt_lpi = INVALID_LPI;
         hlpi.dom_id = d->domain_id;
-        hlpi.vcpu_id = INVALID_VCPU_ID;
         write_u64_atomic(&lpi_data.host_lpis[chunk][lpi_idx + i].data,
                          hlpi.data);
 
-- 
2.9.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* [PATCH v11 14/34] ARM: GICv3: forward pending LPIs to guests
  2017-06-09 17:41 [PATCH v11 00/34] arm64: Dom0 ITS emulation Andre Przywara
                   ` (12 preceding siblings ...)
  2017-06-09 17:41 ` [PATCH v11 13/34] ARM: GIC: ITS: remove no longer needed VCPU ID in host LPI entry Andre Przywara
@ 2017-06-09 17:41 ` Andre Przywara
  2017-06-12 15:53   ` Julien Grall
  2017-06-09 17:41 ` [PATCH v11 15/34] ARM: vGICv3: handle virtual LPI pending and property tables Andre Przywara
                   ` (20 subsequent siblings)
  34 siblings, 1 reply; 71+ messages in thread
From: Andre Przywara @ 2017-06-09 17:41 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

Upon receiving an LPI on the host, we need to find the right VCPU and
virtual IRQ number to get this IRQ injected.
Iterate our two-level LPI table to find the domain ID and the virtual
LPI number quickly when the host takes an LPI. We then look up the
right VCPU in the struct pending_irq.
We use the existing injection function to let the GIC emulation deal
with this interrupt.
This introduces a do_LPI() as a hardware gic_ops.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 xen/arch/arm/gic-v2.c            |  7 ++++
 xen/arch/arm/gic-v3-lpi.c        | 79 ++++++++++++++++++++++++++++++++++++++++
 xen/arch/arm/gic-v3.c            |  1 +
 xen/arch/arm/gic.c               |  8 +++-
 xen/include/asm-arm/domain.h     |  3 +-
 xen/include/asm-arm/gic.h        |  2 +
 xen/include/asm-arm/gic_v3_its.h | 10 +++++
 7 files changed, 108 insertions(+), 2 deletions(-)

diff --git a/xen/arch/arm/gic-v2.c b/xen/arch/arm/gic-v2.c
index 270a136..ffbe47c 100644
--- a/xen/arch/arm/gic-v2.c
+++ b/xen/arch/arm/gic-v2.c
@@ -1217,6 +1217,12 @@ static int __init gicv2_init(void)
     return 0;
 }
 
+static void gicv2_do_LPI(unsigned int lpi)
+{
+    /* No LPIs in a GICv2 */
+    BUG();
+}
+
 const static struct gic_hw_operations gicv2_ops = {
     .info                = &gicv2_info,
     .init                = gicv2_init,
@@ -1244,6 +1250,7 @@ const static struct gic_hw_operations gicv2_ops = {
     .make_hwdom_madt     = gicv2_make_hwdom_madt,
     .map_hwdom_extra_mappings = gicv2_map_hwdown_extra_mappings,
     .iomem_deny_access   = gicv2_iomem_deny_access,
+    .do_LPI              = gicv2_do_LPI,
 };
 
 /* Set up the GIC */
diff --git a/xen/arch/arm/gic-v3-lpi.c b/xen/arch/arm/gic-v3-lpi.c
index dbaf45a..03d23b6 100644
--- a/xen/arch/arm/gic-v3-lpi.c
+++ b/xen/arch/arm/gic-v3-lpi.c
@@ -136,6 +136,85 @@ uint64_t gicv3_get_redist_address(unsigned int cpu, bool use_pta)
         return per_cpu(lpi_redist, cpu).redist_id << 16;
 }
 
+void vgic_vcpu_inject_lpi(struct domain *d, unsigned int virq)
+{
+    /*
+     * TODO: this assumes that the struct pending_irq stays valid all of
+     * time. We cannot properly protect this with the current locking
+     * scheme, but the future per-IRQ lock will solve this problem.
+     */
+    struct pending_irq *p = irq_to_pending(d->vcpu[0], virq);
+    unsigned int vcpu_id;
+
+    if ( !p )
+        return;
+
+    vcpu_id = ACCESS_ONCE(p->lpi_vcpu_id);
+    if ( vcpu_id >= d->max_vcpus )
+          return;
+
+    vgic_vcpu_inject_irq(d->vcpu[vcpu_id], virq);
+}
+
+/*
+ * Handle incoming LPIs, which are a bit special, because they are potentially
+ * numerous and also only get injected into guests. Treat them specially here,
+ * by just looking up their target vCPU and virtual LPI number and hand it
+ * over to the injection function.
+ * Please note that LPIs are edge-triggered only, also have no active state,
+ * so spurious interrupts on the host side are no issue (we can just ignore
+ * them).
+ * Also a guest cannot expect that firing interrupts that haven't been
+ * fully configured yet will reach the CPU, so we don't need to care about
+ * this special case.
+ */
+void gicv3_do_LPI(unsigned int lpi)
+{
+    struct domain *d;
+    union host_lpi *hlpip, hlpi;
+
+    irq_enter();
+
+    /* EOI the LPI already. */
+    WRITE_SYSREG32(lpi, ICC_EOIR1_EL1);
+
+    /* Find out if a guest mapped something to this physical LPI. */
+    hlpip = gic_get_host_lpi(lpi);
+    if ( !hlpip )
+        goto out;
+
+    hlpi.data = read_u64_atomic(&hlpip->data);
+
+    /*
+     * Unmapped events are marked with an invalid LPI ID. We can safely
+     * ignore them, as they have no further state and no-one can expect
+     * to see them if they have not been mapped.
+     */
+    if ( hlpi.virt_lpi == INVALID_LPI )
+        goto out;
+
+    d = rcu_lock_domain_by_id(hlpi.dom_id);
+    if ( !d )
+        goto out;
+
+    /*
+     * TODO: Investigate what to do here for potential interrupt storms.
+     * As we keep all host LPIs enabled, for disabling LPIs we would need
+     * to queue a ITS host command, which we avoid so far during a guest's
+     * runtime. Also re-enabling would trigger a host command upon the
+     * guest sending a command, which could be an attack vector for
+     * hogging the host command queue.
+     * See the thread around here for some background:
+     * https://lists.xen.org/archives/html/xen-devel/2016-12/msg00003.html
+     */
+    vgic_vcpu_inject_lpi(d, hlpi.virt_lpi);
+
+    rcu_unlock_domain(d);
+
+out:
+    irq_exit();
+}
+
 static int gicv3_lpi_allocate_pendtable(uint64_t *reg)
 {
     uint64_t val;
diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c
index fc3614e..d539d6c 100644
--- a/xen/arch/arm/gic-v3.c
+++ b/xen/arch/arm/gic-v3.c
@@ -1692,6 +1692,7 @@ static const struct gic_hw_operations gicv3_ops = {
     .make_hwdom_dt_node  = gicv3_make_hwdom_dt_node,
     .make_hwdom_madt     = gicv3_make_hwdom_madt,
     .iomem_deny_access   = gicv3_iomem_deny_access,
+    .do_LPI              = gicv3_do_LPI,
 };
 
 static int __init gicv3_dt_preinit(struct dt_device_node *node, const void *data)
diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index 36e340b..9597ef8 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -732,7 +732,13 @@ void gic_interrupt(struct cpu_user_regs *regs, int is_fiq)
             do_IRQ(regs, irq, is_fiq);
             local_irq_disable();
         }
-        else if (unlikely(irq < 16))
+        else if ( is_lpi(irq) )
+        {
+            local_irq_enable();
+            gic_hw_ops->do_LPI(irq);
+            local_irq_disable();
+        }
+        else if ( unlikely(irq < 16) )
         {
             do_sgi(regs, irq);
         }
diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
index 3d8e84c..ebaea35 100644
--- a/xen/include/asm-arm/domain.h
+++ b/xen/include/asm-arm/domain.h
@@ -260,7 +260,8 @@ struct arch_vcpu
 
         /* GICv3: redistributor base and flags for this vCPU */
         paddr_t rdist_base;
-#define VGIC_V3_RDIST_LAST  (1 << 0)        /* last vCPU of the rdist */
+#define VGIC_V3_RDIST_LAST      (1 << 0)        /* last vCPU of the rdist */
+#define VGIC_V3_LPIS_ENABLED    (1 << 1)
         uint8_t flags;
     } vgic;
 
diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
index 5d5b4cc..783937b 100644
--- a/xen/include/asm-arm/gic.h
+++ b/xen/include/asm-arm/gic.h
@@ -367,6 +367,8 @@ struct gic_hw_operations {
     int (*map_hwdom_extra_mappings)(struct domain *d);
     /* Deny access to GIC regions */
     int (*iomem_deny_access)(const struct domain *d);
+    /* Handle LPIs, which require special handling */
+    void (*do_LPI)(unsigned int lpi);
 };
 
 void register_gic_ops(const struct gic_hw_operations *ops);
diff --git a/xen/include/asm-arm/gic_v3_its.h b/xen/include/asm-arm/gic_v3_its.h
index 29559a3..a659184 100644
--- a/xen/include/asm-arm/gic_v3_its.h
+++ b/xen/include/asm-arm/gic_v3_its.h
@@ -134,6 +134,8 @@ void gicv3_its_dt_init(const struct dt_device_node *node);
 
 bool gicv3_its_host_has_its(void);
 
+void gicv3_do_LPI(unsigned int lpi);
+
 int gicv3_lpi_init_rdist(void __iomem * rdist_base);
 
 /* Initialize the host structures for LPIs and the host ITSes. */
@@ -164,6 +166,8 @@ int gicv3_its_map_guest_device(struct domain *d,
 int gicv3_allocate_host_lpi_block(struct domain *d, uint32_t *first_lpi);
 void gicv3_free_host_lpi_block(uint32_t first_lpi);
 
+void vgic_vcpu_inject_lpi(struct domain *d, unsigned int virq);
+
 #else
 
 static inline void gicv3_its_dt_init(const struct dt_device_node *node)
@@ -175,6 +179,12 @@ static inline bool gicv3_its_host_has_its(void)
     return false;
 }
 
+static inline void gicv3_do_LPI(unsigned int lpi)
+{
+    /* We don't enable LPIs without an ITS. */
+    BUG();
+}
+
 static inline int gicv3_lpi_init_rdist(void __iomem * rdist_base)
 {
     return -ENODEV;
-- 
2.9.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* [PATCH v11 15/34] ARM: vGICv3: handle virtual LPI pending and property tables
  2017-06-09 17:41 [PATCH v11 00/34] arm64: Dom0 ITS emulation Andre Przywara
                   ` (13 preceding siblings ...)
  2017-06-09 17:41 ` [PATCH v11 14/34] ARM: GICv3: forward pending LPIs to guests Andre Przywara
@ 2017-06-09 17:41 ` Andre Przywara
  2017-06-09 17:41 ` [PATCH v11 16/34] ARM: introduce vgic_access_guest_memory() Andre Przywara
                   ` (19 subsequent siblings)
  34 siblings, 0 replies; 71+ messages in thread
From: Andre Przywara @ 2017-06-09 17:41 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

Allow a guest to provide the address and size for the memory regions
it has reserved for the GICv3 pending and property tables.
We sanitise the various fields of the respective redistributor
registers.
The MMIO read and write accesses are protected by locks, to avoid any
changing of the property or pending table address while a redistributor
is live and also to protect the non-atomic vgic_reg64_extract() function
on the MMIO read side.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Reviewed-by: Julien Grall <julien.grall@arm.com>
---
 xen/arch/arm/vgic-v3.c       | 164 +++++++++++++++++++++++++++++++++++++++----
 xen/include/asm-arm/domain.h |   9 +++
 2 files changed, 161 insertions(+), 12 deletions(-)

diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
index 66a758c..c571ea9 100644
--- a/xen/arch/arm/vgic-v3.c
+++ b/xen/arch/arm/vgic-v3.c
@@ -233,12 +233,29 @@ static int __vgic_v3_rdistr_rd_mmio_read(struct vcpu *v, mmio_info_t *info,
         goto read_reserved;
 
     case VREG64(GICR_PROPBASER):
-        /* LPI's not implemented */
-        goto read_as_zero_64;
+        if ( !v->domain->arch.vgic.has_its )
+            goto read_as_zero_64;
+        if ( !vgic_reg64_check_access(dabt) ) goto bad_width;
+
+        vgic_lock(v);
+        *r = vgic_reg64_extract(v->domain->arch.vgic.rdist_propbase, info);
+        vgic_unlock(v);
+        return 1;
 
     case VREG64(GICR_PENDBASER):
-        /* LPI's not implemented */
-        goto read_as_zero_64;
+    {
+        unsigned long flags;
+
+        if ( !v->domain->arch.vgic.has_its )
+            goto read_as_zero_64;
+        if ( !vgic_reg64_check_access(dabt) ) goto bad_width;
+
+        spin_lock_irqsave(&v->arch.vgic.lock, flags);
+        *r = vgic_reg64_extract(v->arch.vgic.rdist_pendbase, info);
+        *r &= ~GICR_PENDBASER_PTZ;       /* WO, reads as 0 */
+        spin_unlock_irqrestore(&v->arch.vgic.lock, flags);
+        return 1;
+    }
 
     case 0x0080:
         goto read_reserved;
@@ -335,11 +352,95 @@ read_unknown:
     return 1;
 }
 
+static uint64_t vgic_sanitise_field(uint64_t reg, uint64_t field_mask,
+                                    int field_shift,
+                                    uint64_t (*sanitise_fn)(uint64_t))
+{
+    uint64_t field = (reg & field_mask) >> field_shift;
+
+    field = sanitise_fn(field) << field_shift;
+
+    return (reg & ~field_mask) | field;
+}
+
+/* We want to avoid outer shareable. */
+static uint64_t vgic_sanitise_shareability(uint64_t field)
+{
+    switch ( field )
+    {
+    case GIC_BASER_OuterShareable:
+        return GIC_BASER_InnerShareable;
+    default:
+        return field;
+    }
+}
+
+/* Avoid any inner non-cacheable mapping. */
+static uint64_t vgic_sanitise_inner_cacheability(uint64_t field)
+{
+    switch ( field )
+    {
+    case GIC_BASER_CACHE_nCnB:
+    case GIC_BASER_CACHE_nC:
+        return GIC_BASER_CACHE_RaWb;
+    default:
+        return field;
+    }
+}
+
+/* Non-cacheable or same-as-inner are OK. */
+static uint64_t vgic_sanitise_outer_cacheability(uint64_t field)
+{
+    switch ( field )
+    {
+    case GIC_BASER_CACHE_SameAsInner:
+    case GIC_BASER_CACHE_nC:
+        return field;
+    default:
+        return GIC_BASER_CACHE_nC;
+    }
+}
+
+static uint64_t sanitize_propbaser(uint64_t reg)
+{
+    reg = vgic_sanitise_field(reg, GICR_PROPBASER_SHAREABILITY_MASK,
+                              GICR_PROPBASER_SHAREABILITY_SHIFT,
+                              vgic_sanitise_shareability);
+    reg = vgic_sanitise_field(reg, GICR_PROPBASER_INNER_CACHEABILITY_MASK,
+                              GICR_PROPBASER_INNER_CACHEABILITY_SHIFT,
+                              vgic_sanitise_inner_cacheability);
+    reg = vgic_sanitise_field(reg, GICR_PROPBASER_OUTER_CACHEABILITY_MASK,
+                              GICR_PROPBASER_OUTER_CACHEABILITY_SHIFT,
+                              vgic_sanitise_outer_cacheability);
+
+    reg &= ~GICR_PROPBASER_RES0_MASK;
+
+    return reg;
+}
+
+static uint64_t sanitize_pendbaser(uint64_t reg)
+{
+    reg = vgic_sanitise_field(reg, GICR_PENDBASER_SHAREABILITY_MASK,
+                              GICR_PENDBASER_SHAREABILITY_SHIFT,
+                              vgic_sanitise_shareability);
+    reg = vgic_sanitise_field(reg, GICR_PENDBASER_INNER_CACHEABILITY_MASK,
+                              GICR_PENDBASER_INNER_CACHEABILITY_SHIFT,
+                              vgic_sanitise_inner_cacheability);
+    reg = vgic_sanitise_field(reg, GICR_PENDBASER_OUTER_CACHEABILITY_MASK,
+                              GICR_PENDBASER_OUTER_CACHEABILITY_SHIFT,
+                              vgic_sanitise_outer_cacheability);
+
+    reg &= ~GICR_PENDBASER_RES0_MASK;
+
+    return reg;
+}
+
 static int __vgic_v3_rdistr_rd_mmio_write(struct vcpu *v, mmio_info_t *info,
                                           uint32_t gicr_reg,
                                           register_t r)
 {
     struct hsr_dabt dabt = info->dabt;
+    uint64_t reg;
 
     switch ( gicr_reg )
     {
@@ -370,36 +471,75 @@ static int __vgic_v3_rdistr_rd_mmio_write(struct vcpu *v, mmio_info_t *info,
         goto write_impl_defined;
 
     case VREG64(GICR_SETLPIR):
-        /* LPI is not implemented */
+        /* LPIs without an ITS are not implemented */
         goto write_ignore_64;
 
     case VREG64(GICR_CLRLPIR):
-        /* LPI is not implemented */
+        /* LPIs without an ITS are not implemented */
         goto write_ignore_64;
 
     case 0x0050:
         goto write_reserved;
 
     case VREG64(GICR_PROPBASER):
-        /* LPI is not implemented */
-        goto write_ignore_64;
+        if ( !v->domain->arch.vgic.has_its )
+            goto write_ignore_64;
+        if ( !vgic_reg64_check_access(dabt) ) goto bad_width;
+
+        vgic_lock(v);
+
+        /*
+         * Writing PROPBASER with any redistributor having LPIs enabled
+         * is UNPREDICTABLE.
+         */
+        if ( !(v->domain->arch.vgic.rdists_enabled) )
+        {
+            reg = v->domain->arch.vgic.rdist_propbase;
+            vgic_reg64_update(&reg, r, info);
+            reg = sanitize_propbaser(reg);
+            v->domain->arch.vgic.rdist_propbase = reg;
+        }
+
+        vgic_unlock(v);
+
+        return 1;
 
     case VREG64(GICR_PENDBASER):
-        /* LPI is not implemented */
-        goto write_ignore_64;
+    {
+        unsigned long flags;
+
+        if ( !v->domain->arch.vgic.has_its )
+            goto write_ignore_64;
+        if ( !vgic_reg64_check_access(dabt) ) goto bad_width;
+
+        spin_lock_irqsave(&v->arch.vgic.lock, flags);
+
+        /* Writing PENDBASER with LPIs enabled is UNPREDICTABLE. */
+        if ( !(v->arch.vgic.flags & VGIC_V3_LPIS_ENABLED) )
+        {
+            reg = v->arch.vgic.rdist_pendbase;
+            vgic_reg64_update(&reg, r, info);
+            reg = sanitize_pendbaser(reg);
+            v->arch.vgic.rdist_pendbase = reg;
+        }
+
+        spin_unlock_irqrestore(&v->arch.vgic.lock, false);
+
+        return 1;
+    }
 
     case 0x0080:
         goto write_reserved;
 
     case VREG64(GICR_INVLPIR):
-        /* LPI is not implemented */
+        /* LPIs without an ITS are not implemented */
         goto write_ignore_64;
 
     case 0x00A8:
         goto write_reserved;
 
     case VREG64(GICR_INVALLR):
-        /* LPI is not implemented */
+        /* LPIs without an ITS are not implemented */
         goto write_ignore_64;
 
     case 0x00B8:
diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
index ebaea35..b33f54a 100644
--- a/xen/include/asm-arm/domain.h
+++ b/xen/include/asm-arm/domain.h
@@ -109,11 +109,19 @@ struct arch_domain
         } *rdist_regions;
         int nr_regions;                     /* Number of rdist regions */
         uint32_t rdist_stride;              /* Re-Distributor stride */
+        unsigned long int nr_lpis;
+        uint64_t rdist_propbase;
         struct rb_root its_devices;         /* Devices mapped to an ITS */
         spinlock_t its_devices_lock;        /* Protects the its_devices tree */
         struct radix_tree_root pend_lpi_tree; /* Stores struct pending_irq's */
         rwlock_t pend_lpi_tree_lock;        /* Protects the pend_lpi_tree */
         unsigned int intid_bits;
+        /*
+         * TODO: if there are more bool's being added below, consider
+         * a flags variable instead.
+         */
+        bool rdists_enabled;                /* Is any redistributor enabled? */
+        bool has_its;
 #endif
     } vgic;
 
@@ -260,6 +268,7 @@ struct arch_vcpu
 
         /* GICv3: redistributor base and flags for this vCPU */
         paddr_t rdist_base;
+        uint64_t rdist_pendbase;
 #define VGIC_V3_RDIST_LAST      (1 << 0)        /* last vCPU of the rdist */
 #define VGIC_V3_LPIS_ENABLED    (1 << 1)
         uint8_t flags;
-- 
2.9.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* [PATCH v11 16/34] ARM: introduce vgic_access_guest_memory()
  2017-06-09 17:41 [PATCH v11 00/34] arm64: Dom0 ITS emulation Andre Przywara
                   ` (14 preceding siblings ...)
  2017-06-09 17:41 ` [PATCH v11 15/34] ARM: vGICv3: handle virtual LPI pending and property tables Andre Przywara
@ 2017-06-09 17:41 ` Andre Przywara
  2017-06-09 17:41 ` [PATCH v11 17/34] ARM: vGICv3: re-use vgic_reg64_check_access Andre Przywara
                   ` (18 subsequent siblings)
  34 siblings, 0 replies; 71+ messages in thread
From: Andre Przywara @ 2017-06-09 17:41 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>

This function allows to copy a chunk of data from and to guest physical
memory. It looks up the associated page from the guest's p2m tree
and maps this page temporarily for the time of the access.
This function was originally written by Vijaya as part of an earlier series:
https://patchwork.kernel.org/patch/8177251

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Reviewed-by: Julien Grall <julien.grall@arm.com>
---
 xen/arch/arm/vgic.c        | 50 ++++++++++++++++++++++++++++++++++++++++++++++
 xen/include/asm-arm/vgic.h |  3 +++
 2 files changed, 53 insertions(+)

diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
index 546f412..9bfe8cb 100644
--- a/xen/arch/arm/vgic.c
+++ b/xen/arch/arm/vgic.c
@@ -20,6 +20,7 @@
 #include <xen/bitops.h>
 #include <xen/lib.h>
 #include <xen/init.h>
+#include <xen/domain_page.h>
 #include <xen/softirq.h>
 #include <xen/irq.h>
 #include <xen/sched.h>
@@ -637,6 +638,55 @@ void vgic_free_virq(struct domain *d, unsigned int virq)
 }
 
 /*
+ * Temporarily map one physical guest page and copy data to or from it.
+ * The data to be copied cannot cross a page boundary.
+ */
+int vgic_access_guest_memory(struct domain *d, paddr_t gpa, void *buf,
+                             uint32_t size, bool is_write)
+{
+    struct page_info *page;
+    uint64_t offset = gpa & ~PAGE_MASK;  /* Offset within the mapped page */
+    p2m_type_t p2mt;
+    void *p;
+
+    /* Do not cross a page boundary. */
+    if ( size > (PAGE_SIZE - offset) )
+    {
+        printk(XENLOG_G_ERR "d%d: vITS: memory access would cross page boundary\n",
+               d->domain_id);
+        return -EINVAL;
+    }
+
+    page = get_page_from_gfn(d, paddr_to_pfn(gpa), &p2mt, P2M_ALLOC);
+    if ( !page )
+    {
+        printk(XENLOG_G_ERR "d%d: vITS: Failed to get table entry\n",
+               d->domain_id);
+        return -EINVAL;
+    }
+
+    if ( !p2m_is_ram(p2mt) )
+    {
+        put_page(page);
+        printk(XENLOG_G_ERR "d%d: vITS: memory used by the ITS should be RAM.",
+               d->domain_id);
+        return -EINVAL;
+    }
+
+    p = __map_domain_page(page);
+
+    if ( is_write )
+        memcpy(p + offset, buf, size);
+    else
+        memcpy(buf, p + offset, size);
+
+    unmap_domain_page(p);
+    put_page(page);
+
+    return 0;
+}
+
+/*
  * Local variables:
  * mode: C
  * c-file-style: "BSD"
diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h
index 07b56dc..02732db 100644
--- a/xen/include/asm-arm/vgic.h
+++ b/xen/include/asm-arm/vgic.h
@@ -315,6 +315,9 @@ extern void register_vgic_ops(struct domain *d, const struct vgic_ops *ops);
 int vgic_v2_init(struct domain *d, int *mmio_count);
 int vgic_v3_init(struct domain *d, int *mmio_count);
 
+int vgic_access_guest_memory(struct domain *d, paddr_t gpa, void *buf,
+                             uint32_t size, bool_t is_write);
+
 extern int domain_vgic_register(struct domain *d, int *mmio_count);
 extern int vcpu_vgic_free(struct vcpu *v);
 extern bool vgic_to_sgi(struct vcpu *v, register_t sgir,
-- 
2.9.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* [PATCH v11 17/34] ARM: vGICv3: re-use vgic_reg64_check_access
  2017-06-09 17:41 [PATCH v11 00/34] arm64: Dom0 ITS emulation Andre Przywara
                   ` (15 preceding siblings ...)
  2017-06-09 17:41 ` [PATCH v11 16/34] ARM: introduce vgic_access_guest_memory() Andre Przywara
@ 2017-06-09 17:41 ` Andre Przywara
  2017-06-09 17:41 ` [PATCH v11 18/34] ARM: vGIC: advertise LPI support Andre Przywara
                   ` (17 subsequent siblings)
  34 siblings, 0 replies; 71+ messages in thread
From: Andre Przywara @ 2017-06-09 17:41 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

vgic_reg64_check_access() checks for a valid access width of a 64-bit
MMIO register, which is useful beyond the current GICv3 emulation only.
Move this function to the vgic-emul.h to be easily reusable.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Acked-by: Julien Grall <julien.grall@arm.com>
---
 xen/arch/arm/vgic-v3.c          | 9 ---------
 xen/include/asm-arm/vgic-emul.h | 9 +++++++++
 2 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
index c571ea9..f32e419 100644
--- a/xen/arch/arm/vgic-v3.c
+++ b/xen/arch/arm/vgic-v3.c
@@ -161,15 +161,6 @@ static void vgic_store_irouter(struct domain *d, struct vgic_irq_rank *rank,
     }
 }
 
-static inline bool vgic_reg64_check_access(struct hsr_dabt dabt)
-{
-    /*
-     * 64 bits registers can be accessible using 32-bit and 64-bit unless
-     * stated otherwise (See 8.1.3 ARM IHI 0069A).
-     */
-    return ( dabt.size == DABT_DOUBLE_WORD || dabt.size == DABT_WORD );
-}
-
 static int __vgic_v3_rdistr_rd_mmio_read(struct vcpu *v, mmio_info_t *info,
                                          uint32_t gicr_reg,
                                          register_t *r)
diff --git a/xen/include/asm-arm/vgic-emul.h b/xen/include/asm-arm/vgic-emul.h
index 184a1f0..e52fbaa 100644
--- a/xen/include/asm-arm/vgic-emul.h
+++ b/xen/include/asm-arm/vgic-emul.h
@@ -12,6 +12,15 @@
 #define VRANGE32(start, end) start ... end + 3
 #define VRANGE64(start, end) start ... end + 7
 
+/*
+ * 64 bits registers can be accessible using 32-bit and 64-bit unless
+ * stated otherwise (See 8.1.3 ARM IHI 0069A).
+ */
+static inline bool vgic_reg64_check_access(struct hsr_dabt dabt)
+{
+    return ( dabt.size == DABT_DOUBLE_WORD || dabt.size == DABT_WORD );
+}
+
 #endif /* __ASM_ARM_VGIC_EMUL_H__ */
 
 /*
-- 
2.9.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* [PATCH v11 18/34] ARM: vGIC: advertise LPI support
  2017-06-09 17:41 [PATCH v11 00/34] arm64: Dom0 ITS emulation Andre Przywara
                   ` (16 preceding siblings ...)
  2017-06-09 17:41 ` [PATCH v11 17/34] ARM: vGICv3: re-use vgic_reg64_check_access Andre Przywara
@ 2017-06-09 17:41 ` Andre Przywara
  2017-06-12 16:02   ` Julien Grall
  2017-06-09 17:41 ` [PATCH v11 19/34] ARM: vITS: add command handling stub and MMIO emulation Andre Przywara
                   ` (16 subsequent siblings)
  34 siblings, 1 reply; 71+ messages in thread
From: Andre Przywara @ 2017-06-09 17:41 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

To let a guest know about the availability of virtual LPIs, set the
respective bits in the virtual GIC registers and let a guest control
the LPI enable bit.
Only report the LPI capability if there is at least one ITS emulated
for that guest (which depends on the host having an ITS at the moment).
For Dom0 we report the same number of interrupts identifiers as the
host, whereas DomUs get a number fixed at 10 bits for the moments, which
covers all SPIs. Also we fix a slight inaccuracy here, since the
number of interrupt identifier specified in GICD_TYPER depends on the
stream interface and is independent from the number of actually wired
SPIs.
This also removes a "TBD" comment, as we now populate the processor
number in the GICR_TYPER register, which will be used by the ITS
emulation later on.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 xen/arch/arm/vgic-v3.c | 83 +++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 76 insertions(+), 7 deletions(-)

diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
index f32e419..296991a 100644
--- a/xen/arch/arm/vgic-v3.c
+++ b/xen/arch/arm/vgic-v3.c
@@ -170,8 +170,19 @@ static int __vgic_v3_rdistr_rd_mmio_read(struct vcpu *v, mmio_info_t *info,
     switch ( gicr_reg )
     {
     case VREG32(GICR_CTLR):
-        /* We have not implemented LPI's, read zero */
-        goto read_as_zero_32;
+    {
+        unsigned long flags;
+
+        if ( !v->domain->arch.vgic.has_its )
+            goto read_as_zero_32;
+        if ( dabt.size != DABT_WORD ) goto bad_width;
+
+        spin_lock_irqsave(&v->arch.vgic.lock, flags);
+        *r = vgic_reg32_extract(!!(v->arch.vgic.flags & VGIC_V3_LPIS_ENABLED),
+                                info);
+        spin_unlock_irqrestore(&v->arch.vgic.lock, flags);
+        return 1;
+    }
 
     case VREG32(GICR_IIDR):
         if ( dabt.size != DABT_WORD ) goto bad_width;
@@ -183,16 +194,20 @@ static int __vgic_v3_rdistr_rd_mmio_read(struct vcpu *v, mmio_info_t *info,
         uint64_t typer, aff;
 
         if ( !vgic_reg64_check_access(dabt) ) goto bad_width;
-        /* TBD: Update processor id in [23:8] when ITS support is added */
         aff = (MPIDR_AFFINITY_LEVEL(v->arch.vmpidr, 3) << 56 |
                MPIDR_AFFINITY_LEVEL(v->arch.vmpidr, 2) << 48 |
                MPIDR_AFFINITY_LEVEL(v->arch.vmpidr, 1) << 40 |
                MPIDR_AFFINITY_LEVEL(v->arch.vmpidr, 0) << 32);
         typer = aff;
+        /* We use the VCPU ID as the redistributor ID in bits[23:8] */
+        typer |= v->vcpu_id << GICR_TYPER_PROC_NUM_SHIFT;
 
         if ( v->arch.vgic.flags & VGIC_V3_RDIST_LAST )
             typer |= GICR_TYPER_LAST;
 
+        if ( v->domain->arch.vgic.has_its )
+            typer |= GICR_TYPER_PLPIS;
+
         *r = vgic_reg64_extract(typer, info);
 
         return 1;
@@ -426,6 +441,40 @@ static uint64_t sanitize_pendbaser(uint64_t reg)
     return reg;
 }
 
+static void vgic_vcpu_enable_lpis(struct vcpu *v)
+{
+    uint64_t reg = v->domain->arch.vgic.rdist_propbase;
+    unsigned int nr_lpis = BIT((reg & 0x1f) + 1);
+
+    /* rdists_enabled is protected by the domain lock. */
+    ASSERT(spin_is_locked(&v->domain->arch.vgic.lock));
+
+    if ( nr_lpis < LPI_OFFSET )
+        nr_lpis = 0;
+    else
+        nr_lpis -= LPI_OFFSET;
+
+    if ( !v->domain->arch.vgic.rdists_enabled )
+    {
+        v->domain->arch.vgic.nr_lpis = nr_lpis;
+        /*
+         * Make sure nr_lpis is visible before rdists_enabled.
+         * We read nr_lpis (and rdist_propbase) outside of the lock in
+         * other functions, but guard those accesses by rdists_enabled, so
+         * make sure these are consistent.
+         */
+        smp_mb();
+        v->domain->arch.vgic.rdists_enabled = true;
+        /*
+         * Make sure the per-domain rdists_enabled flag has been set before
+         * enabling this particular redistributor.
+         */
+        smp_mb();
+    }
+
+    v->arch.vgic.flags |= VGIC_V3_LPIS_ENABLED;
+}
+
 static int __vgic_v3_rdistr_rd_mmio_write(struct vcpu *v, mmio_info_t *info,
                                           uint32_t gicr_reg,
                                           register_t r)
@@ -436,8 +485,26 @@ static int __vgic_v3_rdistr_rd_mmio_write(struct vcpu *v, mmio_info_t *info,
     switch ( gicr_reg )
     {
     case VREG32(GICR_CTLR):
-        /* LPI's not implemented */
-        goto write_ignore_32;
+    {
+        unsigned long flags;
+
+        if ( !v->domain->arch.vgic.has_its )
+            goto write_ignore_32;
+        if ( dabt.size != DABT_WORD ) goto bad_width;
+
+        vgic_lock(v);                   /* protects rdists_enabled */
+        spin_lock_irqsave(&v->arch.vgic.lock, flags);
+
+        /* LPIs can only be enabled once, but never disabled again. */
+        if ( (r & GICR_CTLR_ENABLE_LPIS) &&
+             !(v->arch.vgic.flags & VGIC_V3_LPIS_ENABLED) )
+            vgic_vcpu_enable_lpis(v);
+
+        spin_unlock_irqrestore(&v->arch.vgic.lock, flags);
+        vgic_unlock(v);
+
+        return 1;
+    }
 
     case VREG32(GICR_IIDR):
         /* RO */
@@ -1048,7 +1115,6 @@ static int vgic_v3_distr_mmio_read(struct vcpu *v, mmio_info_t *info,
          * Number of interrupt identifier bits supported by the GIC
          * Stream Protocol Interface
          */
-        unsigned int irq_bits = get_count_order(vgic_num_irqs(v->domain));
         /*
          * Number of processors that may be used as interrupt targets when ARE
          * bit is zero. The maximum is 8.
@@ -1061,7 +1127,10 @@ static int vgic_v3_distr_mmio_read(struct vcpu *v, mmio_info_t *info,
         typer = ((ncpus - 1) << GICD_TYPE_CPUS_SHIFT |
                  DIV_ROUND_UP(v->domain->arch.vgic.nr_spis, 32));
 
-        typer |= (irq_bits - 1) << GICD_TYPE_ID_BITS_SHIFT;
+        if ( v->domain->arch.vgic.has_its )
+            typer |= GICD_TYPE_LPIS;
+
+        typer |= (v->domain->arch.vgic.intid_bits - 1) << GICD_TYPE_ID_BITS_SHIFT;
 
         *r = vgic_reg32_extract(typer, info);
 
-- 
2.9.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* [PATCH v11 19/34] ARM: vITS: add command handling stub and MMIO emulation
  2017-06-09 17:41 [PATCH v11 00/34] arm64: Dom0 ITS emulation Andre Przywara
                   ` (17 preceding siblings ...)
  2017-06-09 17:41 ` [PATCH v11 18/34] ARM: vGIC: advertise LPI support Andre Przywara
@ 2017-06-09 17:41 ` Andre Przywara
  2017-06-12 16:04   ` Julien Grall
  2017-06-09 17:41 ` [PATCH v11 20/34] ARM: vITS: introduce translation table walks Andre Przywara
                   ` (15 subsequent siblings)
  34 siblings, 1 reply; 71+ messages in thread
From: Andre Przywara @ 2017-06-09 17:41 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

Emulate the memory mapped ITS registers and provide a stub to introduce
the ITS command handling framework (but without actually emulating any
commands at this time).
This fixes a misnomer in our virtual ITS structure, where the spec is
confusingly using ID_bits in GITS_TYPER to denote the number of event IDs
(in contrast to GICD_TYPER, where it means number of LPIs).

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 xen/arch/arm/vgic-v3-its.c       | 588 ++++++++++++++++++++++++++++++++++++++-
 xen/include/asm-arm/gic_v3_its.h |   3 +
 2 files changed, 590 insertions(+), 1 deletion(-)

diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
index 065ffe2..5481791 100644
--- a/xen/arch/arm/vgic-v3-its.c
+++ b/xen/arch/arm/vgic-v3-its.c
@@ -19,6 +19,16 @@
  * along with this program; If not, see <http://www.gnu.org/licenses/>.
  */
 
+/*
+ * Locking order:
+ *
+ * its->vcmd_lock                        (protects the command queue)
+ *     its->its_lock                     (protects the translation tables)
+ *         d->its_devices_lock           (protects the device RB tree)
+ *             v->vgic.lock              (protects the struct pending_irq)
+ *                 d->pend_lpi_tree_lock (protects the radix tree)
+ */
+
 #include <xen/bitops.h>
 #include <xen/config.h>
 #include <xen/domain_page.h>
@@ -43,7 +53,7 @@
 struct virt_its {
     struct domain *d;
     unsigned int devid_bits;
-    unsigned int intid_bits;
+    unsigned int evid_bits;
     spinlock_t vcmd_lock;       /* Protects the virtual command buffer, which */
     uint64_t cwriter;           /* consists of CWRITER and CREADR and those   */
     uint64_t creadr;            /* shadow variables cwriter and creadr. */
@@ -53,6 +63,7 @@ struct virt_its {
     uint64_t baser_dev, baser_coll;     /* BASER0 and BASER1 for the guest */
     unsigned int max_collections;
     unsigned int max_devices;
+    /* changing "enabled" requires to hold *both* the vcmd_lock and its_lock */
     bool enabled;
 };
 
@@ -67,6 +78,581 @@ struct vits_itte
     uint16_t pad;
 };
 
+/*
+ * Our collection table encoding:
+ * Each entry just contains the VCPU ID of the respective vCPU.
+ */
+typedef uint16_t coll_table_entry_t;
+
+/*
+ * Our device table encodings:
+ * Contains the guest physical address of the Interrupt Translation Table in
+ * bits [51:8], and the size of it is encoded as the number of bits minus one
+ * in the lowest 5 bits of the word.
+ */
+typedef uint64_t dev_table_entry_t;
+#define DEV_TABLE_ITT_ADDR(x) ((x) & GENMASK(51, 8))
+#define DEV_TABLE_ITT_SIZE(x) (BIT(((x) & GENMASK(4, 0)) + 1))
+#define DEV_TABLE_ENTRY(addr, bits)                     \
+        (((addr) & GENMASK(51, 8)) | (((bits) - 1) & GENMASK(4, 0)))
+
+#define GITS_BASER_RO_MASK       (GITS_BASER_TYPE_MASK | \
+                                  (0x1fL << GITS_BASER_ENTRY_SIZE_SHIFT))
+
+/**************************************
+ * Functions that handle ITS commands *
+ **************************************/
+
+static uint64_t its_cmd_mask_field(uint64_t *its_cmd, unsigned int word,
+                                   unsigned int shift, unsigned int size)
+{
+    return (its_cmd[word] >> shift) & GENMASK(size - 1, 0);
+}
+
+#define its_cmd_get_command(cmd)        its_cmd_mask_field(cmd, 0,  0,  8)
+#define its_cmd_get_deviceid(cmd)       its_cmd_mask_field(cmd, 0, 32, 32)
+#define its_cmd_get_size(cmd)           its_cmd_mask_field(cmd, 1,  0,  5)
+#define its_cmd_get_id(cmd)             its_cmd_mask_field(cmd, 1,  0, 32)
+#define its_cmd_get_physical_id(cmd)    its_cmd_mask_field(cmd, 1, 32, 32)
+#define its_cmd_get_collection(cmd)     its_cmd_mask_field(cmd, 2,  0, 16)
+#define its_cmd_get_target_addr(cmd)    its_cmd_mask_field(cmd, 2, 16, 32)
+#define its_cmd_get_validbit(cmd)       its_cmd_mask_field(cmd, 2, 63,  1)
+#define its_cmd_get_ittaddr(cmd)        (its_cmd_mask_field(cmd, 2, 8, 44) << 8)
+
+#define ITS_CMD_BUFFER_SIZE(baser)      ((((baser) & 0xff) + 1) << 12)
+#define ITS_CMD_OFFSET(reg)             ((reg) & GENMASK(19, 5))
+
+static void dump_its_command(uint64_t *command)
+{
+    gdprintk(XENLOG_WARNING, "  cmd 0x%02lx: %016lx %016lx %016lx %016lx\n",
+             its_cmd_get_command(command),
+             command[0], command[1], command[2], command[3]);
+}
+
+/*
+ * Must be called with the vcmd_lock held.
+ * TODO: Investigate whether we can be smarter here and don't need to hold
+ * the lock all of the time.
+ */
+static int vgic_its_handle_cmds(struct domain *d, struct virt_its *its)
+{
+    paddr_t addr = its->cbaser & GENMASK(51, 12);
+    uint64_t command[4];
+
+    ASSERT(spin_is_locked(&its->vcmd_lock));
+
+    if ( its->cwriter >= ITS_CMD_BUFFER_SIZE(its->cbaser) )
+        return -1;
+
+    while ( its->creadr != its->cwriter )
+    {
+        int ret;
+
+        ret = vgic_access_guest_memory(d, addr + its->creadr,
+                                       command, sizeof(command), false);
+        if ( ret )
+            return ret;
+
+        switch ( its_cmd_get_command(command) )
+        {
+        case GITS_CMD_SYNC:
+            /* We handle ITS commands synchronously, so we ignore SYNC. */
+            break;
+        default:
+            gdprintk(XENLOG_WARNING, "vGITS: unhandled ITS command\n");
+            dump_its_command(command);
+            break;
+        }
+
+        write_u64_atomic(&its->creadr, (its->creadr + ITS_CMD_SIZE) %
+                         ITS_CMD_BUFFER_SIZE(its->cbaser));
+
+        if ( ret )
+        {
+            gdprintk(XENLOG_WARNING,
+                     "vGITS: ITS command error %d while handling command\n",
+                     ret);
+            dump_its_command(command);
+        }
+    }
+
+    return 0;
+}
+
+/*****************************
+ * ITS registers read access *
+ *****************************/
+
+/* Identifying as an ARM IP, using "X" as the product ID. */
+#define GITS_IIDR_VALUE                 0x5800034c
+
+static int vgic_v3_its_mmio_read(struct vcpu *v, mmio_info_t *info,
+                                 register_t *r, void *priv)
+{
+    struct virt_its *its = priv;
+    uint64_t reg;
+
+    switch ( info->gpa & 0xffff )
+    {
+    case VREG32(GITS_CTLR):
+    {
+        /*
+         * We try to avoid waiting for the command queue lock and report
+         * non-quiescent if that lock is already taken.
+         */
+        bool have_cmd_lock;
+
+        if ( info->dabt.size != DABT_WORD ) goto bad_width;
+
+        have_cmd_lock = spin_trylock(&its->vcmd_lock);
+        reg = its->enabled ? GITS_CTLR_ENABLE : 0;
+
+        if ( have_cmd_lock && its->cwriter == its->creadr )
+            reg |= GITS_CTLR_QUIESCENT;
+
+        if ( have_cmd_lock )
+            spin_unlock(&its->vcmd_lock);
+
+        *r = vgic_reg32_extract(reg, info);
+        break;
+    }
+
+    case VREG32(GITS_IIDR):
+        if ( info->dabt.size != DABT_WORD ) goto bad_width;
+        *r = vgic_reg32_extract(GITS_IIDR_VALUE, info);
+        break;
+
+    case VREG64(GITS_TYPER):
+        if ( !vgic_reg64_check_access(info->dabt) ) goto bad_width;
+
+        reg = GITS_TYPER_PHYSICAL;
+        reg |= (sizeof(struct vits_itte) - 1) << GITS_TYPER_ITT_SIZE_SHIFT;
+        reg |= (its->evid_bits - 1) << GITS_TYPER_IDBITS_SHIFT;
+        reg |= (its->devid_bits - 1) << GITS_TYPER_DEVIDS_SHIFT;
+        *r = vgic_reg64_extract(reg, info);
+        break;
+
+    case VRANGE32(0x0018, 0x001C):
+        goto read_reserved;
+    case VRANGE32(0x0020, 0x003C):
+        goto read_impl_defined;
+    case VRANGE32(0x0040, 0x007C):
+        goto read_reserved;
+
+    case VREG64(GITS_CBASER):
+        if ( !vgic_reg64_check_access(info->dabt) ) goto bad_width;
+        spin_lock(&its->its_lock);
+        *r = vgic_reg64_extract(its->cbaser, info);
+        spin_unlock(&its->its_lock);
+        break;
+
+    case VREG64(GITS_CWRITER):
+        if ( !vgic_reg64_check_access(info->dabt) ) goto bad_width;
+
+        /* CWRITER is only written by the guest, so no extra locking here. */
+        reg = its->cwriter;
+        *r = vgic_reg64_extract(reg, info);
+        break;
+
+    case VREG64(GITS_CREADR):
+        if ( !vgic_reg64_check_access(info->dabt) ) goto bad_width;
+
+        /*
+         * Lockless access, to avoid waiting for the whole command queue to be
+         * finished completely. Xen updates its->creadr atomically after each
+         * command has been handled, this allows other VCPUs to monitor the
+         * progress.
+         */
+        reg = read_u64_atomic(&its->creadr);
+        *r = vgic_reg64_extract(reg, info);
+        break;
+
+    case VRANGE64(0x0098, 0x00F8):
+        goto read_reserved;
+
+    case VREG64(GITS_BASER0):           /* device table */
+        if ( !vgic_reg64_check_access(info->dabt) ) goto bad_width;
+        spin_lock(&its->its_lock);
+        *r = vgic_reg64_extract(its->baser_dev, info);
+        spin_unlock(&its->its_lock);
+        break;
+
+    case VREG64(GITS_BASER1):           /* collection table */
+        if ( !vgic_reg64_check_access(info->dabt) ) goto bad_width;
+        spin_lock(&its->its_lock);
+        *r = vgic_reg64_extract(its->baser_coll, info);
+        spin_unlock(&its->its_lock);
+        break;
+
+    case VRANGE64(GITS_BASER2, GITS_BASER7):
+        goto read_as_zero_64;
+    case VRANGE32(0x0140, 0xBFFC):
+        goto read_reserved;
+    case VRANGE32(0xC000, 0xFFCC):
+        goto read_impl_defined;
+    case VRANGE32(0xFFD0, 0xFFE4):
+        goto read_impl_defined;
+
+    case VREG32(GITS_PIDR2):
+        if ( info->dabt.size != DABT_WORD ) goto bad_width;
+        *r = vgic_reg32_extract(GIC_PIDR2_ARCH_GICv3, info);
+        break;
+
+    case VRANGE32(0xFFEC, 0xFFFC):
+        goto read_impl_defined;
+
+    default:
+        printk(XENLOG_G_ERR
+               "%pv: vGITS: unhandled read r%d offset %#04lx\n",
+               v, info->dabt.reg, (unsigned long)info->gpa & 0xffff);
+        return 0;
+    }
+
+    return 1;
+
+read_as_zero_64:
+    if ( !vgic_reg64_check_access(info->dabt) ) goto bad_width;
+    *r = 0;
+
+    return 1;
+
+read_impl_defined:
+    printk(XENLOG_G_DEBUG
+           "%pv: vGITS: RAZ on implementation defined register offset %#04lx\n",
+           v, info->gpa & 0xffff);
+    *r = 0;
+    return 1;
+
+read_reserved:
+    printk(XENLOG_G_DEBUG
+           "%pv: vGITS: RAZ on reserved register offset %#04lx\n",
+           v, info->gpa & 0xffff);
+    *r = 0;
+    return 1;
+
+bad_width:
+    printk(XENLOG_G_ERR "vGITS: bad read width %d r%d offset %#04lx\n",
+           info->dabt.size, info->dabt.reg, (unsigned long)info->gpa & 0xffff);
+    domain_crash_synchronous();
+
+    return 0;
+}
+
+/******************************
+ * ITS registers write access *
+ ******************************/
+
+static unsigned int its_baser_table_size(uint64_t baser)
+{
+    unsigned int ret, page_size[4] = {SZ_4K, SZ_16K, SZ_64K, SZ_64K};
+
+    ret = page_size[(baser >> GITS_BASER_PAGE_SIZE_SHIFT) & 3];
+
+    return ret * ((baser & GITS_BASER_SIZE_MASK) + 1);
+}
+
+static unsigned int its_baser_nr_entries(uint64_t baser)
+{
+    unsigned int entry_size = GITS_BASER_ENTRY_SIZE(baser);
+
+    return its_baser_table_size(baser) / entry_size;
+}
+
+/* Must be called with the ITS lock held. */
+static bool vgic_v3_verify_its_status(struct virt_its *its, bool status)
+{
+    ASSERT(spin_is_locked(&its->its_lock));
+
+    if ( !status )
+        return false;
+
+    if ( !(its->cbaser & GITS_VALID_BIT) ||
+         !(its->baser_dev & GITS_VALID_BIT) ||
+         !(its->baser_coll & GITS_VALID_BIT) )
+    {
+        printk(XENLOG_G_WARNING "d%d tried to enable ITS without having the tables configured.\n",
+               its->d->domain_id);
+        return false;
+    }
+
+    /*
+     * TODO: Protect against a guest crafting ITS tables.
+     * The spec says that "at the time of the new allocation for use by the ITS"
+     * all tables must contain zeroes. We could enforce this here by clearing
+     * all the tables, but this would be moot since at the moment the guest
+     * can change the tables at any point in time anyway. Right now there are
+     * expectations about the tables being consistent (a VCPU lock protecting
+     * an LPI), which should go away with proper per-IRQ locking.
+     * So for now we ignore this issue and rely on Dom0 not doing bad things.
+     */
+    ASSERT(is_hardware_domain(its->d));
+
+    return true;
+}
+
+static void sanitize_its_base_reg(uint64_t *reg)
+{
+    uint64_t r = *reg;
+
+    /* Avoid outer shareable. */
+    switch ( (r >> GITS_BASER_SHAREABILITY_SHIFT) & 0x03 )
+    {
+    case GIC_BASER_OuterShareable:
+        r &= ~GITS_BASER_SHAREABILITY_MASK;
+        r |= GIC_BASER_InnerShareable << GITS_BASER_SHAREABILITY_SHIFT;
+        break;
+    default:
+        break;
+    }
+
+    /* Avoid any inner non-cacheable mapping. */
+    switch ( (r >> GITS_BASER_INNER_CACHEABILITY_SHIFT) & 0x07 )
+    {
+    case GIC_BASER_CACHE_nCnB:
+    case GIC_BASER_CACHE_nC:
+        r &= ~GITS_BASER_INNER_CACHEABILITY_MASK;
+        r |= GIC_BASER_CACHE_RaWb << GITS_BASER_INNER_CACHEABILITY_SHIFT;
+        break;
+    default:
+        break;
+    }
+
+    /* Only allow non-cacheable or same-as-inner. */
+    switch ( (r >> GITS_BASER_OUTER_CACHEABILITY_SHIFT) & 0x07 )
+    {
+    case GIC_BASER_CACHE_SameAsInner:
+    case GIC_BASER_CACHE_nC:
+        break;
+    default:
+        r &= ~GITS_BASER_OUTER_CACHEABILITY_MASK;
+        r |= GIC_BASER_CACHE_nC << GITS_BASER_OUTER_CACHEABILITY_SHIFT;
+        break;
+    }
+
+    *reg = r;
+}
+
+static int vgic_v3_its_mmio_write(struct vcpu *v, mmio_info_t *info,
+                                  register_t r, void *priv)
+{
+    struct domain *d = v->domain;
+    struct virt_its *its = priv;
+    uint64_t reg;
+    uint32_t reg32;
+
+    switch ( info->gpa & 0xffff )
+    {
+    case VREG32(GITS_CTLR):
+    {
+        uint32_t ctlr;
+
+        if ( info->dabt.size != DABT_WORD ) goto bad_width;
+
+        /*
+         * We need to take the vcmd_lock to prevent a guest from disabling
+         * the ITS while commands are still processed.
+         */
+        spin_lock(&its->vcmd_lock);
+        spin_lock(&its->its_lock);
+        ctlr = its->enabled ? GITS_CTLR_ENABLE : 0;
+        reg32 = ctlr;
+        vgic_reg32_update(&reg32, r, info);
+
+        if ( ctlr ^ reg32 )
+            its->enabled = vgic_v3_verify_its_status(its,
+                                                     reg32 & GITS_CTLR_ENABLE);
+        spin_unlock(&its->its_lock);
+        spin_unlock(&its->vcmd_lock);
+        return 1;
+    }
+
+    case VREG32(GITS_IIDR):
+        goto write_ignore_32;
+
+    case VREG32(GITS_TYPER):
+        goto write_ignore_32;
+
+    case VRANGE32(0x0018, 0x001C):
+        goto write_reserved;
+    case VRANGE32(0x0020, 0x003C):
+        goto write_impl_defined;
+    case VRANGE32(0x0040, 0x007C):
+        goto write_reserved;
+
+    case VREG64(GITS_CBASER):
+        if ( !vgic_reg64_check_access(info->dabt) ) goto bad_width;
+
+        spin_lock(&its->its_lock);
+        /* Changing base registers with the ITS enabled is UNPREDICTABLE. */
+        if ( its->enabled )
+        {
+            spin_unlock(&its->its_lock);
+            gdprintk(XENLOG_WARNING,
+                     "vGITS: tried to change CBASER with the ITS enabled.\n");
+            return 1;
+        }
+
+        reg = its->cbaser;
+        vgic_reg64_update(&reg, r, info);
+        sanitize_its_base_reg(&reg);
+
+        its->cbaser = reg;
+        its->creadr = 0;
+        spin_unlock(&its->its_lock);
+
+        return 1;
+
+    case VREG64(GITS_CWRITER):
+        if ( !vgic_reg64_check_access(info->dabt) ) goto bad_width;
+
+        spin_lock(&its->vcmd_lock);
+        reg = ITS_CMD_OFFSET(its->cwriter);
+        vgic_reg64_update(&reg, r, info);
+        its->cwriter = ITS_CMD_OFFSET(reg);
+
+        if ( its->enabled )
+            if ( vgic_its_handle_cmds(d, its) )
+                gdprintk(XENLOG_WARNING, "error handling ITS commands\n");
+
+        spin_unlock(&its->vcmd_lock);
+
+        return 1;
+
+    case VREG64(GITS_CREADR):
+        goto write_ignore_64;
+
+    case VRANGE32(0x0098, 0x00FC):
+        goto write_reserved;
+
+    case VREG64(GITS_BASER0):           /* device table */
+        if ( !vgic_reg64_check_access(info->dabt) ) goto bad_width;
+
+        spin_lock(&its->its_lock);
+
+        /*
+         * Changing base registers with the ITS enabled is UNPREDICTABLE,
+         * we choose to ignore it, but warn.
+         */
+        if ( its->enabled )
+        {
+            spin_unlock(&its->its_lock);
+            gdprintk(XENLOG_WARNING, "vGITS: tried to change BASER with the ITS enabled.\n");
+
+            return 1;
+        }
+
+        reg = its->baser_dev;
+        vgic_reg64_update(&reg, r, info);
+
+        /* We don't support indirect tables for now. */
+        reg &= ~(GITS_BASER_RO_MASK | GITS_BASER_INDIRECT);
+        reg |= (sizeof(dev_table_entry_t) - 1) << GITS_BASER_ENTRY_SIZE_SHIFT;
+        reg |= GITS_BASER_TYPE_DEVICE << GITS_BASER_TYPE_SHIFT;
+        sanitize_its_base_reg(&reg);
+
+        if ( reg & GITS_VALID_BIT )
+        {
+            its->max_devices = its_baser_nr_entries(reg);
+            if ( its->max_devices > BIT(its->devid_bits) )
+                its->max_devices = BIT(its->devid_bits);
+        }
+        else
+            its->max_devices = 0;
+
+        its->baser_dev = reg;
+        spin_unlock(&its->its_lock);
+        return 1;
+
+    case VREG64(GITS_BASER1):           /* collection table */
+        if ( !vgic_reg64_check_access(info->dabt) ) goto bad_width;
+
+        spin_lock(&its->its_lock);
+        /*
+         * Changing base registers with the ITS enabled is UNPREDICTABLE,
+         * we choose to ignore it, but warn.
+         */
+        if ( its->enabled )
+        {
+            spin_unlock(&its->its_lock);
+            gdprintk(XENLOG_INFO, "vGITS: tried to change BASER with the ITS enabled.\n");
+            return 1;
+        }
+
+        reg = its->baser_coll;
+        vgic_reg64_update(&reg, r, info);
+        /* No indirect tables for the collection table. */
+        reg &= ~(GITS_BASER_RO_MASK | GITS_BASER_INDIRECT);
+        reg |= (sizeof(coll_table_entry_t) - 1) << GITS_BASER_ENTRY_SIZE_SHIFT;
+        reg |= GITS_BASER_TYPE_COLLECTION << GITS_BASER_TYPE_SHIFT;
+        sanitize_its_base_reg(&reg);
+
+        if ( reg & GITS_VALID_BIT )
+            its->max_collections = its_baser_nr_entries(reg);
+        else
+            its->max_collections = 0;
+        its->baser_coll = reg;
+        spin_unlock(&its->its_lock);
+        return 1;
+
+    case VRANGE64(GITS_BASER2, GITS_BASER7):
+        goto write_ignore_64;
+
+    case VRANGE32(0x0140, 0xBFFC):
+        goto write_reserved;
+    case VRANGE32(0xC000, 0xFFCC):
+        goto write_impl_defined;
+    case VRANGE32(0xFFD0, 0xFFE4):      /* IMPDEF identification registers */
+        goto write_impl_defined;
+
+    case VREG32(GITS_PIDR2):
+        goto write_ignore_32;
+
+    case VRANGE32(0xFFEC, 0xFFFC):      /* IMPDEF identification registers */
+        goto write_impl_defined;
+
+    default:
+        printk(XENLOG_G_ERR
+               "%pv: vGITS: unhandled write r%d offset %#04lx\n",
+               v, info->dabt.reg, (unsigned long)info->gpa & 0xffff);
+        return 0;
+    }
+
+    return 1;
+
+write_ignore_64:
+    if ( !vgic_reg64_check_access(info->dabt) ) goto bad_width;
+    return 1;
+
+write_ignore_32:
+    if ( info->dabt.size != DABT_WORD ) goto bad_width;
+    return 1;
+
+write_impl_defined:
+    printk(XENLOG_G_DEBUG
+           "%pv: vGITS: WI on implementation defined register offset %#04lx\n",
+           v, info->gpa & 0xffff);
+    return 1;
+
+write_reserved:
+    printk(XENLOG_G_DEBUG
+           "%pv: vGITS: WI on implementation defined register offset %#04lx\n",
+           v, info->gpa & 0xffff);
+    return 1;
+
+bad_width:
+    printk(XENLOG_G_ERR "vGITS: bad write width %d r%d offset %#08lx\n",
+           info->dabt.size, info->dabt.reg, (unsigned long)info->gpa & 0xffff);
+
+    domain_crash_synchronous();
+
+    return 0;
+}
+
+static const struct mmio_handler_ops vgic_its_mmio_handler = {
+    .read  = vgic_v3_its_mmio_read,
+    .write = vgic_v3_its_mmio_write,
+};
+
 int vgic_v3_its_init_domain(struct domain *d)
 {
     spin_lock_init(&d->arch.vgic.its_devices_lock);
diff --git a/xen/include/asm-arm/gic_v3_its.h b/xen/include/asm-arm/gic_v3_its.h
index a659184..5db7d04 100644
--- a/xen/include/asm-arm/gic_v3_its.h
+++ b/xen/include/asm-arm/gic_v3_its.h
@@ -35,6 +35,7 @@
 #define GITS_BASER5                     0x128
 #define GITS_BASER6                     0x130
 #define GITS_BASER7                     0x138
+#define GITS_PIDR2                      GICR_PIDR2
 
 /* Register bits */
 #define GITS_VALID_BIT                  BIT(63)
@@ -57,6 +58,7 @@
 #define GITS_TYPER_ITT_SIZE_MASK        (0xfUL << GITS_TYPER_ITT_SIZE_SHIFT)
 #define GITS_TYPER_ITT_SIZE(r)          ((((r) & GITS_TYPER_ITT_SIZE_MASK) >> \
                                                  GITS_TYPER_ITT_SIZE_SHIFT) + 1)
+#define GITS_TYPER_PHYSICAL             (1U << 0)
 
 #define GITS_BASER_INDIRECT             BIT(62)
 #define GITS_BASER_INNER_CACHEABILITY_SHIFT        59
@@ -76,6 +78,7 @@
                         (((reg >> GITS_BASER_ENTRY_SIZE_SHIFT) & 0x1f) + 1)
 #define GITS_BASER_SHAREABILITY_SHIFT   10
 #define GITS_BASER_PAGE_SIZE_SHIFT      8
+#define GITS_BASER_SIZE_MASK            0xff
 #define GITS_BASER_SHAREABILITY_MASK   (0x3ULL << GITS_BASER_SHAREABILITY_SHIFT)
 #define GITS_BASER_OUTER_CACHEABILITY_MASK   (0x7ULL << GITS_BASER_OUTER_CACHEABILITY_SHIFT)
 #define GITS_BASER_INNER_CACHEABILITY_MASK   (0x7ULL << GITS_BASER_INNER_CACHEABILITY_SHIFT)
-- 
2.9.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* [PATCH v11 20/34] ARM: vITS: introduce translation table walks
  2017-06-09 17:41 [PATCH v11 00/34] arm64: Dom0 ITS emulation Andre Przywara
                   ` (18 preceding siblings ...)
  2017-06-09 17:41 ` [PATCH v11 19/34] ARM: vITS: add command handling stub and MMIO emulation Andre Przywara
@ 2017-06-09 17:41 ` Andre Przywara
  2017-06-12 16:07   ` Julien Grall
  2017-06-09 17:41 ` [PATCH v11 21/34] ARM: vITS: provide access to struct pending_irq Andre Przywara
                   ` (14 subsequent siblings)
  34 siblings, 1 reply; 71+ messages in thread
From: Andre Przywara @ 2017-06-09 17:41 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

The ITS stores the target (v)CPU and the (virtual) LPI number in tables.
Introduce functions to walk those tables and translate an device ID -
event ID pair into a pair of virtual LPI and vCPU.
We map those tables on demand - which is cheap on arm64 - and copy the
respective entries before using them, to avoid the guest tampering with
them meanwhile.

To allow compiling without warnings, we declare two functions as
non-static for the moment, which two later patches will fix.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 xen/arch/arm/vgic-v3-its.c | 140 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 140 insertions(+)

diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
index 5481791..36910aa 100644
--- a/xen/arch/arm/vgic-v3-its.c
+++ b/xen/arch/arm/vgic-v3-its.c
@@ -83,6 +83,7 @@ struct vits_itte
  * Each entry just contains the VCPU ID of the respective vCPU.
  */
 typedef uint16_t coll_table_entry_t;
+#define UNMAPPED_COLLECTION      ((coll_table_entry_t)~0)
 
 /*
  * Our device table encodings:
@@ -99,6 +100,145 @@ typedef uint64_t dev_table_entry_t;
 #define GITS_BASER_RO_MASK       (GITS_BASER_TYPE_MASK | \
                                   (0x1fL << GITS_BASER_ENTRY_SIZE_SHIFT))
 
+/*
+ * The physical address is encoded slightly differently depending on
+ * the used page size: the highest four bits are stored in the lowest
+ * four bits of the field for 64K pages.
+ */
+static paddr_t get_baser_phys_addr(uint64_t reg)
+{
+    if ( reg & BIT(9) )
+        return (reg & GENMASK(47, 16)) |
+                ((reg & GENMASK(15, 12)) << 36);
+    else
+        return reg & GENMASK(47, 12);
+}
+
+/* Must be called with the ITS lock held. */
+static struct vcpu *get_vcpu_from_collection(struct virt_its *its,
+                                             uint16_t collid)
+{
+    paddr_t addr = get_baser_phys_addr(its->baser_coll);
+    coll_table_entry_t vcpu_id;
+    int ret;
+
+    ASSERT(spin_is_locked(&its->its_lock));
+
+    if ( collid >= its->max_collections )
+        return NULL;
+
+    ret = vgic_access_guest_memory(its->d,
+                                   addr + collid * sizeof(coll_table_entry_t),
+                                   &vcpu_id, sizeof(coll_table_entry_t), false);
+    if ( ret )
+        return NULL;
+
+    if ( vcpu_id == UNMAPPED_COLLECTION || vcpu_id >= its->d->max_vcpus )
+        return NULL;
+
+    return its->d->vcpu[vcpu_id];
+}
+
+/*
+ * Lookup the address of the Interrupt Translation Table associated with
+ * that device ID.
+ * TODO: add support for walking indirect tables.
+ */
+static int its_get_itt(struct virt_its *its, uint32_t devid,
+                       dev_table_entry_t *itt)
+{
+    paddr_t addr = get_baser_phys_addr(its->baser_dev);
+
+    if ( devid >= its->max_devices )
+        return -EINVAL;
+
+    return vgic_access_guest_memory(its->d,
+                                    addr + devid * sizeof(dev_table_entry_t),
+                                    itt, sizeof(*itt), false);
+}
+
+/*
+ * Lookup the address of the Interrupt Translation Table associated with
+ * a device ID and return the address of the ITTE belonging to the event ID
+ * (which is an index into that table).
+ */
+static paddr_t its_get_itte_address(struct virt_its *its,
+                                    uint32_t devid, uint32_t evid)
+{
+    dev_table_entry_t itt;
+    int ret;
+
+    ret = its_get_itt(its, devid, &itt);
+    if ( ret )
+        return INVALID_PADDR;
+
+    if ( evid >= DEV_TABLE_ITT_SIZE(itt) ||
+         DEV_TABLE_ITT_ADDR(itt) == INVALID_PADDR )
+        return INVALID_PADDR;
+
+    return DEV_TABLE_ITT_ADDR(itt) + evid * sizeof(struct vits_itte);
+}
+
+/*
+ * Queries the collection and device tables to get the vCPU and virtual
+ * LPI number for a given guest event. This first accesses the guest memory
+ * to resolve the address of the ITTE, then reads the ITTE entry at this
+ * address and puts the result in vcpu_ptr and vlpi_ptr.
+ * Must be called with the ITS lock held.
+ */
+bool read_itte(struct virt_its *its, uint32_t devid, uint32_t evid,
+               struct vcpu **vcpu_ptr, uint32_t *vlpi_ptr)
+{
+    paddr_t addr;
+    struct vits_itte itte;
+    struct vcpu *vcpu;
+
+    ASSERT(spin_is_locked(&its->its_lock));
+
+    addr = its_get_itte_address(its, devid, evid);
+    if ( addr == INVALID_PADDR )
+        return false;
+
+    if ( vgic_access_guest_memory(its->d, addr, &itte, sizeof(itte), false) )
+        return false;
+
+    vcpu = get_vcpu_from_collection(its, itte.collection);
+    if ( !vcpu )
+        return false;
+
+    *vcpu_ptr = vcpu;
+    *vlpi_ptr = itte.vlpi;
+    return true;
+}
+
+/*
+ * Queries the collection and device tables to translate the device ID and
+ * event ID and find the appropriate ITTE. The given collection ID and the
+ * virtual LPI number are then stored into that entry.
+ * If vcpu_ptr is provided, returns the VCPU belonging to that collection.
+ * Must be called with the ITS lock held.
+ */
+bool write_itte(struct virt_its *its, uint32_t devid,
+                uint32_t evid, uint32_t collid, uint32_t vlpi)
+{
+    paddr_t addr;
+    struct vits_itte itte;
+
+    ASSERT(spin_is_locked(&its->its_lock));
+
+    addr = its_get_itte_address(its, devid, evid);
+    if ( addr == INVALID_PADDR )
+        return false;
+
+    itte.collection = collid;
+    itte.vlpi = vlpi;
+
+    if ( vgic_access_guest_memory(its->d, addr, &itte, sizeof(itte), true) )
+        return false;
+
+    return true;
+}
+
 /**************************************
  * Functions that handle ITS commands *
  **************************************/
-- 
2.9.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* [PATCH v11 21/34] ARM: vITS: provide access to struct pending_irq
  2017-06-09 17:41 [PATCH v11 00/34] arm64: Dom0 ITS emulation Andre Przywara
                   ` (19 preceding siblings ...)
  2017-06-09 17:41 ` [PATCH v11 20/34] ARM: vITS: introduce translation table walks Andre Przywara
@ 2017-06-09 17:41 ` Andre Przywara
  2017-06-09 17:41 ` [PATCH v11 22/34] ARM: vITS: handle INT command Andre Przywara
                   ` (13 subsequent siblings)
  34 siblings, 0 replies; 71+ messages in thread
From: Andre Przywara @ 2017-06-09 17:41 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

For each device we allocate one struct pending_irq for each virtual
event (MSI).
Provide a helper function which returns the pointer to the appropriate
struct, to be able to find the right struct when given a virtual
deviceID/eventID pair.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Acked-by: Julien Grall <julien.grall@arm.com>
---
 xen/arch/arm/gic-v3-its.c        | 59 ++++++++++++++++++++++++++++++++++++++++
 xen/include/asm-arm/gic_v3_its.h |  4 +++
 2 files changed, 63 insertions(+)

diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
index aebc257..38f0840 100644
--- a/xen/arch/arm/gic-v3-its.c
+++ b/xen/arch/arm/gic-v3-its.c
@@ -800,6 +800,65 @@ out:
     return ret;
 }
 
+/* Must be called with the its_device_lock held. */
+static struct its_device *get_its_device(struct domain *d, paddr_t vdoorbell,
+                                         uint32_t vdevid)
+{
+    struct rb_node *node = d->arch.vgic.its_devices.rb_node;
+    struct its_device *dev;
+
+    ASSERT(spin_is_locked(&d->arch.vgic.its_devices_lock));
+
+    while (node)
+    {
+        int cmp;
+
+        dev = rb_entry(node, struct its_device, rbnode);
+        cmp = compare_its_guest_devices(dev, vdoorbell, vdevid);
+
+        if ( !cmp )
+            return dev;
+
+        if ( cmp > 0 )
+            node = node->rb_left;
+        else
+            node = node->rb_right;
+    }
+
+    return NULL;
+}
+
+static struct pending_irq *get_event_pending_irq(struct domain *d,
+                                                 paddr_t vdoorbell_address,
+                                                 uint32_t vdevid,
+                                                 uint32_t eventid,
+                                                 uint32_t *host_lpi)
+{
+    struct its_device *dev;
+    struct pending_irq *pirq = NULL;
+
+    spin_lock(&d->arch.vgic.its_devices_lock);
+    dev = get_its_device(d, vdoorbell_address, vdevid);
+    if ( dev && eventid < dev->eventids )
+    {
+        pirq = &dev->pend_irqs[eventid];
+        if ( host_lpi )
+            *host_lpi = dev->host_lpi_blocks[eventid / LPI_BLOCK] +
+                        (eventid % LPI_BLOCK);
+    }
+    spin_unlock(&d->arch.vgic.its_devices_lock);
+
+    return pirq;
+}
+
+struct pending_irq *gicv3_its_get_event_pending_irq(struct domain *d,
+                                                    paddr_t vdoorbell_address,
+                                                    uint32_t vdevid,
+                                                    uint32_t eventid)
+{
+    return get_event_pending_irq(d, vdoorbell_address, vdevid, eventid, NULL);
+}
+
 /* Scan the DT for any ITS nodes and create a list of host ITSes out of it. */
 void gicv3_its_dt_init(const struct dt_device_node *node)
 {
diff --git a/xen/include/asm-arm/gic_v3_its.h b/xen/include/asm-arm/gic_v3_its.h
index 5db7d04..be67726 100644
--- a/xen/include/asm-arm/gic_v3_its.h
+++ b/xen/include/asm-arm/gic_v3_its.h
@@ -171,6 +171,10 @@ void gicv3_free_host_lpi_block(uint32_t first_lpi);
 
 void vgic_vcpu_inject_lpi(struct domain *d, unsigned int virq);
 
+struct pending_irq *gicv3_its_get_event_pending_irq(struct domain *d,
+                                                    paddr_t vdoorbell_address,
+                                                    uint32_t vdevid,
+                                                    uint32_t eventid);
 #else
 
 static inline void gicv3_its_dt_init(const struct dt_device_node *node)
-- 
2.9.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* [PATCH v11 22/34] ARM: vITS: handle INT command
  2017-06-09 17:41 [PATCH v11 00/34] arm64: Dom0 ITS emulation Andre Przywara
                   ` (20 preceding siblings ...)
  2017-06-09 17:41 ` [PATCH v11 21/34] ARM: vITS: provide access to struct pending_irq Andre Przywara
@ 2017-06-09 17:41 ` Andre Przywara
  2017-06-09 17:41 ` [PATCH v11 23/34] ARM: vITS: handle MAPC command Andre Przywara
                   ` (12 subsequent siblings)
  34 siblings, 0 replies; 71+ messages in thread
From: Andre Przywara @ 2017-06-09 17:41 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

The INT command sets a given LPI identified by a DeviceID/EventID pair
as pending and thus triggers it to be injected.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Reviewed-by: Julien Grall <julien.grall@arm.com>
---
 xen/arch/arm/vgic-v3-its.c | 29 +++++++++++++++++++++++++++--
 1 file changed, 27 insertions(+), 2 deletions(-)

diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
index 36910aa..8a2a0d2 100644
--- a/xen/arch/arm/vgic-v3-its.c
+++ b/xen/arch/arm/vgic-v3-its.c
@@ -186,8 +186,8 @@ static paddr_t its_get_itte_address(struct virt_its *its,
  * address and puts the result in vcpu_ptr and vlpi_ptr.
  * Must be called with the ITS lock held.
  */
-bool read_itte(struct virt_its *its, uint32_t devid, uint32_t evid,
-               struct vcpu **vcpu_ptr, uint32_t *vlpi_ptr)
+static bool read_itte(struct virt_its *its, uint32_t devid, uint32_t evid,
+                      struct vcpu **vcpu_ptr, uint32_t *vlpi_ptr)
 {
     paddr_t addr;
     struct vits_itte itte;
@@ -259,6 +259,28 @@ static uint64_t its_cmd_mask_field(uint64_t *its_cmd, unsigned int word,
 #define its_cmd_get_validbit(cmd)       its_cmd_mask_field(cmd, 2, 63,  1)
 #define its_cmd_get_ittaddr(cmd)        (its_cmd_mask_field(cmd, 2, 8, 44) << 8)
 
+static int its_handle_int(struct virt_its *its, uint64_t *cmdptr)
+{
+    uint32_t devid = its_cmd_get_deviceid(cmdptr);
+    uint32_t eventid = its_cmd_get_id(cmdptr);
+    struct vcpu *vcpu;
+    uint32_t vlpi;
+    bool ret;
+
+    spin_lock(&its->its_lock);
+    ret = read_itte(its, devid, eventid, &vcpu, &vlpi);
+    spin_unlock(&its->its_lock);
+    if ( !ret )
+        return -1;
+
+    if ( vlpi == INVALID_LPI )
+        return -1;
+
+    vgic_vcpu_inject_lpi(its->d, vlpi);
+
+    return 0;
+}
+
 #define ITS_CMD_BUFFER_SIZE(baser)      ((((baser) & 0xff) + 1) << 12)
 #define ITS_CMD_OFFSET(reg)             ((reg) & GENMASK(19, 5))
 
@@ -295,6 +317,9 @@ static int vgic_its_handle_cmds(struct domain *d, struct virt_its *its)
 
         switch ( its_cmd_get_command(command) )
         {
+        case GITS_CMD_INT:
+            ret = its_handle_int(its, command);
+            break;
         case GITS_CMD_SYNC:
             /* We handle ITS commands synchronously, so we ignore SYNC. */
             break;
-- 
2.9.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* [PATCH v11 23/34] ARM: vITS: handle MAPC command
  2017-06-09 17:41 [PATCH v11 00/34] arm64: Dom0 ITS emulation Andre Przywara
                   ` (21 preceding siblings ...)
  2017-06-09 17:41 ` [PATCH v11 22/34] ARM: vITS: handle INT command Andre Przywara
@ 2017-06-09 17:41 ` Andre Przywara
  2017-06-09 17:41 ` [PATCH v11 24/34] ARM: vITS: handle CLEAR command Andre Przywara
                   ` (11 subsequent siblings)
  34 siblings, 0 replies; 71+ messages in thread
From: Andre Przywara @ 2017-06-09 17:41 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

The MAPC command associates a given collection ID with a given
redistributor, thus mapping collections to VCPUs.
We just store the vcpu_id in the collection table for that.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Acked-by: Julien Grall <julien.grall@arm.com>
---
 xen/arch/arm/vgic-v3-its.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 45 insertions(+)

diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
index 8a2a0d2..14cb1f0 100644
--- a/xen/arch/arm/vgic-v3-its.c
+++ b/xen/arch/arm/vgic-v3-its.c
@@ -115,6 +115,25 @@ static paddr_t get_baser_phys_addr(uint64_t reg)
 }
 
 /* Must be called with the ITS lock held. */
+static int its_set_collection(struct virt_its *its, uint16_t collid,
+                              coll_table_entry_t vcpu_id)
+{
+    paddr_t addr = get_baser_phys_addr(its->baser_coll);
+
+    /* The collection table entry must be able to store a VCPU ID. */
+    BUILD_BUG_ON(BIT(sizeof(coll_table_entry_t) * 8) < MAX_VIRT_CPUS);
+
+    ASSERT(spin_is_locked(&its->its_lock));
+
+    if ( collid >= its->max_collections )
+        return -ENOENT;
+
+    return vgic_access_guest_memory(its->d,
+                                    addr + collid * sizeof(coll_table_entry_t),
+                                    &vcpu_id, sizeof(vcpu_id), true);
+}
+
+/* Must be called with the ITS lock held. */
 static struct vcpu *get_vcpu_from_collection(struct virt_its *its,
                                              uint16_t collid)
 {
@@ -281,6 +300,29 @@ static int its_handle_int(struct virt_its *its, uint64_t *cmdptr)
     return 0;
 }
 
+static int its_handle_mapc(struct virt_its *its, uint64_t *cmdptr)
+{
+    uint32_t collid = its_cmd_get_collection(cmdptr);
+    uint64_t rdbase = its_cmd_mask_field(cmdptr, 2, 16, 44);
+
+    if ( collid >= its->max_collections )
+        return -1;
+
+    if ( rdbase >= its->d->max_vcpus )
+        return -1;
+
+    spin_lock(&its->its_lock);
+
+    if ( its_cmd_get_validbit(cmdptr) )
+        its_set_collection(its, collid, rdbase);
+    else
+        its_set_collection(its, collid, UNMAPPED_COLLECTION);
+
+    spin_unlock(&its->its_lock);
+
+    return 0;
+}
+
 #define ITS_CMD_BUFFER_SIZE(baser)      ((((baser) & 0xff) + 1) << 12)
 #define ITS_CMD_OFFSET(reg)             ((reg) & GENMASK(19, 5))
 
@@ -320,6 +362,9 @@ static int vgic_its_handle_cmds(struct domain *d, struct virt_its *its)
         case GITS_CMD_INT:
             ret = its_handle_int(its, command);
             break;
+        case GITS_CMD_MAPC:
+            ret = its_handle_mapc(its, command);
+            break;
         case GITS_CMD_SYNC:
             /* We handle ITS commands synchronously, so we ignore SYNC. */
             break;
-- 
2.9.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* [PATCH v11 24/34] ARM: vITS: handle CLEAR command
  2017-06-09 17:41 [PATCH v11 00/34] arm64: Dom0 ITS emulation Andre Przywara
                   ` (22 preceding siblings ...)
  2017-06-09 17:41 ` [PATCH v11 23/34] ARM: vITS: handle MAPC command Andre Przywara
@ 2017-06-09 17:41 ` Andre Przywara
  2017-06-12 16:19   ` Julien Grall
  2017-06-09 17:41 ` [PATCH v11 25/34] ARM: vITS: handle MAPD command Andre Przywara
                   ` (10 subsequent siblings)
  34 siblings, 1 reply; 71+ messages in thread
From: Andre Przywara @ 2017-06-09 17:41 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

This introduces the ITS command handler for the CLEAR command, which
clears the pending state of an LPI.
This removes a not-yet injected, but already queued IRQ from a VCPU.
As read_itte() is now eventually used, we add the static keyword.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Acked-by: Julien Grall <julien.grall@arm.com>
---
 xen/arch/arm/vgic-v3-its.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 55 insertions(+)

diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
index 14cb1f0..f6262fc 100644
--- a/xen/arch/arm/vgic-v3-its.c
+++ b/xen/arch/arm/vgic-v3-its.c
@@ -52,6 +52,7 @@
  */
 struct virt_its {
     struct domain *d;
+    paddr_t doorbell_address;
     unsigned int devid_bits;
     unsigned int evid_bits;
     spinlock_t vcmd_lock;       /* Protects the virtual command buffer, which */
@@ -323,6 +324,57 @@ static int its_handle_mapc(struct virt_its *its, uint64_t *cmdptr)
     return 0;
 }
 
+/*
+ * CLEAR removes the pending state from an LPI. */
+static int its_handle_clear(struct virt_its *its, uint64_t *cmdptr)
+{
+    uint32_t devid = its_cmd_get_deviceid(cmdptr);
+    uint32_t eventid = its_cmd_get_id(cmdptr);
+    struct pending_irq *p;
+    struct vcpu *vcpu;
+    uint32_t vlpi;
+    unsigned long flags;
+    int ret = -1;
+
+    spin_lock(&its->its_lock);
+
+    /* Translate the DevID/EvID pair into a vCPU/vLPI pair. */
+    if ( !read_itte(its, devid, eventid, &vcpu, &vlpi) )
+        goto out_unlock;
+
+    p = gicv3_its_get_event_pending_irq(its->d, its->doorbell_address,
+                                        devid, eventid);
+    /* Protect against an invalid LPI number. */
+    if ( unlikely(!p) )
+        goto out_unlock;
+
+    /*
+     * TODO: This relies on the VCPU being correct in the ITS tables.
+     * This can be fixed by either using a per-IRQ lock or by using
+     * the VCPU ID from the pending_irq instead.
+     */
+    spin_lock_irqsave(&vcpu->arch.vgic.lock, flags);
+
+    /*
+     * If the LPI is already visible on the guest, it is too late to
+     * clear the pending state. However this is a benign race that can
+     * happen on real hardware, too: If the LPI has already been forwarded
+     * to a CPU interface, a CLEAR request reaching the redistributor has
+     * no effect on that LPI anymore. Since LPIs are edge triggered and
+     * have no active state, we don't need to care about this here.
+     */
+    if ( !test_bit(GIC_IRQ_GUEST_VISIBLE, &p->status) )
+        gic_remove_irq(vcpu, p);
+
+    spin_unlock_irqrestore(&vcpu->arch.vgic.lock, flags);
+    ret = 0;
+
+out_unlock:
+    spin_unlock(&its->its_lock);
+
+    return ret;
+}
+
 #define ITS_CMD_BUFFER_SIZE(baser)      ((((baser) & 0xff) + 1) << 12)
 #define ITS_CMD_OFFSET(reg)             ((reg) & GENMASK(19, 5))
 
@@ -359,6 +411,9 @@ static int vgic_its_handle_cmds(struct domain *d, struct virt_its *its)
 
         switch ( its_cmd_get_command(command) )
         {
+        case GITS_CMD_CLEAR:
+            ret = its_handle_clear(its, command);
+            break;
         case GITS_CMD_INT:
             ret = its_handle_int(its, command);
             break;
-- 
2.9.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* [PATCH v11 25/34] ARM: vITS: handle MAPD command
  2017-06-09 17:41 [PATCH v11 00/34] arm64: Dom0 ITS emulation Andre Przywara
                   ` (23 preceding siblings ...)
  2017-06-09 17:41 ` [PATCH v11 24/34] ARM: vITS: handle CLEAR command Andre Przywara
@ 2017-06-09 17:41 ` Andre Przywara
  2017-06-13 22:02   ` Stefano Stabellini
  2017-06-09 17:41 ` [PATCH v11 26/34] ARM: GICv3: handle unmapped LPIs Andre Przywara
                   ` (9 subsequent siblings)
  34 siblings, 1 reply; 71+ messages in thread
From: Andre Przywara @ 2017-06-09 17:41 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

The MAPD command maps a device by associating a memory region for
storing ITEs with a certain device ID. Since it features a valid bit,
MAPD also covers the "unmap" functionality, which we also cover here.
We store the given guest physical address in the device table, and, if
this command comes from Dom0, tell the host ITS driver about this new
mapping, so it can issue the corresponding host MAPD command and create
the required tables. We take care of rolling back actions should one
step fail.
Upon unmapping a device we make sure we clean up all associated
resources and release the memory again.
We use our existing guest memory access function to find the right ITT
entry and store the mapping there (in guest memory).

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Acked-by: Julien Grall <julien.grall@arm.com>
---
 xen/arch/arm/gic-v3-its.c        |  17 +++++
 xen/arch/arm/gic-v3-lpi.c        |  17 +++++
 xen/arch/arm/vgic-v3-its.c       | 143 +++++++++++++++++++++++++++++++++++++++
 xen/include/asm-arm/gic_v3_its.h |   5 ++
 4 files changed, 182 insertions(+)

diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
index 38f0840..8864e0b 100644
--- a/xen/arch/arm/gic-v3-its.c
+++ b/xen/arch/arm/gic-v3-its.c
@@ -859,6 +859,23 @@ struct pending_irq *gicv3_its_get_event_pending_irq(struct domain *d,
     return get_event_pending_irq(d, vdoorbell_address, vdevid, eventid, NULL);
 }
 
+int gicv3_remove_guest_event(struct domain *d, paddr_t vdoorbell_address,
+                             uint32_t vdevid, uint32_t eventid)
+{
+    uint32_t host_lpi = INVALID_LPI;
+
+    if ( !get_event_pending_irq(d, vdoorbell_address, vdevid, eventid,
+                                &host_lpi) )
+        return -EINVAL;
+
+    if ( host_lpi == INVALID_LPI )
+        return -EINVAL;
+
+    gicv3_lpi_update_host_entry(host_lpi, d->domain_id, INVALID_LPI);
+
+    return 0;
+}
+
 /* Scan the DT for any ITS nodes and create a list of host ITSes out of it. */
 void gicv3_its_dt_init(const struct dt_device_node *node)
 {
diff --git a/xen/arch/arm/gic-v3-lpi.c b/xen/arch/arm/gic-v3-lpi.c
index 03d23b6..027248d 100644
--- a/xen/arch/arm/gic-v3-lpi.c
+++ b/xen/arch/arm/gic-v3-lpi.c
@@ -215,6 +215,23 @@ out:
     irq_exit();
 }
 
+void gicv3_lpi_update_host_entry(uint32_t host_lpi, int domain_id,
+                                 uint32_t virt_lpi)
+{
+    union host_lpi *hlpip, hlpi;
+
+    ASSERT(host_lpi >= LPI_OFFSET);
+
+    host_lpi -= LPI_OFFSET;
+
+    hlpip = &lpi_data.host_lpis[host_lpi / HOST_LPIS_PER_PAGE][host_lpi % HOST_LPIS_PER_PAGE];
+
+    hlpi.virt_lpi = virt_lpi;
+    hlpi.dom_id = domain_id;
+
+    write_u64_atomic(&hlpip->data, hlpi.data);
+}
+
 static int gicv3_lpi_allocate_pendtable(uint64_t *reg)
 {
     uint64_t val;
diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
index f6262fc..7d4e55c 100644
--- a/xen/arch/arm/vgic-v3-its.c
+++ b/xen/arch/arm/vgic-v3-its.c
@@ -159,6 +159,21 @@ static struct vcpu *get_vcpu_from_collection(struct virt_its *its,
     return its->d->vcpu[vcpu_id];
 }
 
+/* Set the address of an ITT for a given device ID. */
+static int its_set_itt_address(struct virt_its *its, uint32_t devid,
+                               paddr_t itt_address, uint32_t nr_bits)
+{
+    paddr_t addr = get_baser_phys_addr(its->baser_dev);
+    dev_table_entry_t itt_entry = DEV_TABLE_ENTRY(itt_address, nr_bits);
+
+    if ( devid >= its->max_devices )
+        return -ENOENT;
+
+    return vgic_access_guest_memory(its->d,
+                                    addr + devid * sizeof(dev_table_entry_t),
+                                    &itt_entry, sizeof(itt_entry), true);
+}
+
 /*
  * Lookup the address of the Interrupt Translation Table associated with
  * that device ID.
@@ -375,6 +390,131 @@ out_unlock:
     return ret;
 }
 
+/* Must be called with the ITS lock held. */
+static int its_discard_event(struct virt_its *its,
+                             uint32_t vdevid, uint32_t vevid)
+{
+    struct pending_irq *p;
+    unsigned long flags;
+    struct vcpu *vcpu;
+    uint32_t vlpi;
+
+    ASSERT(spin_is_locked(&its->its_lock));
+
+    if ( !read_itte(its, vdevid, vevid, &vcpu, &vlpi) )
+        return -ENOENT;
+
+    if ( vlpi == INVALID_LPI )
+        return -ENOENT;
+
+    /*
+     * TODO: This relies on the VCPU being correct in the ITS tables.
+     * This can be fixed by either using a per-IRQ lock or by using
+     * the VCPU ID from the pending_irq instead.
+     */
+    spin_lock_irqsave(&vcpu->arch.vgic.lock, flags);
+
+    /* Remove the pending_irq from the tree. */
+    write_lock(&its->d->arch.vgic.pend_lpi_tree_lock);
+    p = radix_tree_delete(&its->d->arch.vgic.pend_lpi_tree, vlpi);
+    write_unlock(&its->d->arch.vgic.pend_lpi_tree_lock);
+
+    if ( !p )
+    {
+        spin_unlock_irqrestore(&vcpu->arch.vgic.lock, flags);
+
+        return -ENOENT;
+    }
+
+    /* Cleanup the pending_irq and disconnect it from the LPI. */
+    list_del_init(&p->inflight);
+    list_del_init(&p->lr_queue);
+    vgic_init_pending_irq(p, INVALID_LPI);
+
+    spin_unlock_irqrestore(&vcpu->arch.vgic.lock, flags);
+
+    /* Remove the corresponding host LPI entry */
+    return gicv3_remove_guest_event(its->d, its->doorbell_address,
+                                    vdevid, vevid);
+}
+
+static void its_unmap_device(struct virt_its *its, uint32_t devid)
+{
+    dev_table_entry_t itt;
+    uint64_t evid;
+
+    spin_lock(&its->its_lock);
+
+    if ( its_get_itt(its, devid, &itt) )
+        goto out;
+
+    /*
+     * For DomUs we need to check that the number of events per device
+     * is really limited, otherwise looping over all events can take too
+     * long for a guest. This ASSERT can then be removed if that is
+     * covered.
+     */
+    ASSERT(is_hardware_domain(its->d));
+
+    for ( evid = 0; evid < DEV_TABLE_ITT_SIZE(itt); evid++ )
+        /* Don't care about errors here, clean up as much as possible. */
+        its_discard_event(its, devid, evid);
+
+out:
+    spin_unlock(&its->its_lock);
+}
+
+static int its_handle_mapd(struct virt_its *its, uint64_t *cmdptr)
+{
+    /* size and devid get validated by the functions called below. */
+    uint32_t devid = its_cmd_get_deviceid(cmdptr);
+    unsigned int size = its_cmd_get_size(cmdptr) + 1;
+    bool valid = its_cmd_get_validbit(cmdptr);
+    paddr_t itt_addr = its_cmd_get_ittaddr(cmdptr);
+    int ret;
+
+    /* Sanitize the number of events. */
+    if ( valid && (size > its->evid_bits) )
+        return -1;
+
+    if ( !valid )
+        /* Discard all events and remove pending LPIs. */
+        its_unmap_device(its, devid);
+
+    /*
+     * There is no easy and clean way for Xen to know the ITS device ID of a
+     * particular (PCI) device, so we have to rely on the guest telling
+     * us about it. For *now* we are just using the device ID *Dom0* uses,
+     * because the driver there has the actual knowledge.
+     * Eventually this will be replaced with a dedicated hypercall to
+     * announce pass-through of devices.
+     */
+    if ( is_hardware_domain(its->d) )
+    {
+
+        /*
+         * Dom0's ITSes are mapped 1:1, so both addresses are the same.
+         * Also the device IDs are equal.
+         */
+        ret = gicv3_its_map_guest_device(its->d, its->doorbell_address, devid,
+                                         its->doorbell_address, devid,
+                                         BIT(size), valid);
+        if ( ret && valid )
+            return ret;
+    }
+
+    spin_lock(&its->its_lock);
+
+    if ( valid )
+        ret = its_set_itt_address(its, devid, itt_addr, size);
+    else
+        ret = its_set_itt_address(its, devid, INVALID_PADDR, 1);
+
+    spin_unlock(&its->its_lock);
+
+    return ret;
+}
+
 #define ITS_CMD_BUFFER_SIZE(baser)      ((((baser) & 0xff) + 1) << 12)
 #define ITS_CMD_OFFSET(reg)             ((reg) & GENMASK(19, 5))
 
@@ -420,6 +560,9 @@ static int vgic_its_handle_cmds(struct domain *d, struct virt_its *its)
         case GITS_CMD_MAPC:
             ret = its_handle_mapc(its, command);
             break;
+        case GITS_CMD_MAPD:
+            ret = its_handle_mapd(its, command);
+            break;
         case GITS_CMD_SYNC:
             /* We handle ITS commands synchronously, so we ignore SYNC. */
             break;
diff --git a/xen/include/asm-arm/gic_v3_its.h b/xen/include/asm-arm/gic_v3_its.h
index be67726..0089ac2 100644
--- a/xen/include/asm-arm/gic_v3_its.h
+++ b/xen/include/asm-arm/gic_v3_its.h
@@ -175,6 +175,11 @@ struct pending_irq *gicv3_its_get_event_pending_irq(struct domain *d,
                                                     paddr_t vdoorbell_address,
                                                     uint32_t vdevid,
                                                     uint32_t eventid);
+int gicv3_remove_guest_event(struct domain *d, paddr_t vdoorbell_address,
+                                     uint32_t vdevid, uint32_t eventid);
+void gicv3_lpi_update_host_entry(uint32_t host_lpi, int domain_id,
+                                 uint32_t virt_lpi);
+
 #else
 
 static inline void gicv3_its_dt_init(const struct dt_device_node *node)
-- 
2.9.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* [PATCH v11 26/34] ARM: GICv3: handle unmapped LPIs
  2017-06-09 17:41 [PATCH v11 00/34] arm64: Dom0 ITS emulation Andre Przywara
                   ` (24 preceding siblings ...)
  2017-06-09 17:41 ` [PATCH v11 25/34] ARM: vITS: handle MAPD command Andre Przywara
@ 2017-06-09 17:41 ` Andre Przywara
  2017-06-12 16:30   ` Julien Grall
  2017-06-09 17:41 ` [PATCH v11 27/34] ARM: vITS: handle MAPTI/MAPI command Andre Przywara
                   ` (8 subsequent siblings)
  34 siblings, 1 reply; 71+ messages in thread
From: Andre Przywara @ 2017-06-09 17:41 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

When LPIs get unmapped by a guest, they might still be in some LR of
some VCPU. Nevertheless we remove the corresponding pending_irq
(possibly freeing it), and detect this case (irq_to_pending() returns
NULL) when the LR gets cleaned up later.
However a *new* LPI may get mapped with the same number while the old
LPI is *still* in some LR. To avoid getting the wrong state, we mark
every newly mapped LPI as PRISTINE, which means: has never been in an
LR before. If we detect the LPI in an LR anyway, it must have been an
older one, which we can simply retire.
Before inserting such a PRISTINE LPI into an LR, we must make sure that
it's not already in another LR, as the architecture forbids two
interrupts with the same virtual IRQ number on one CPU.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 xen/arch/arm/gic.c         | 51 ++++++++++++++++++++++++++++++++++++++++++----
 xen/include/asm-arm/vgic.h |  6 ++++++
 2 files changed, 53 insertions(+), 4 deletions(-)

diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index 9597ef8..b337a86 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -375,6 +375,8 @@ static inline void gic_set_lr(int lr, struct pending_irq *p,
 {
     ASSERT(!local_irq_is_enabled());
 
+    clear_bit(GIC_IRQ_GUEST_PRISTINE_LPI, &p->status);
+
     gic_hw_ops->update_lr(lr, p, state);
 
     set_bit(GIC_IRQ_GUEST_VISIBLE, &p->status);
@@ -440,6 +442,40 @@ void gic_raise_inflight_irq(struct vcpu *v, unsigned int virtual_irq)
 #endif
 }
 
+/*
+ * Find an unused LR to insert an IRQ into, starting with the LR given
+ * by @lr. If this new interrupt is a PRISTINE LPI, scan the other LRs to
+ * avoid inserting the same IRQ twice. This situation can occur when an
+ * event gets discarded while the LPI is in an LR, and a new LPI with the
+ * same number gets mapped quickly afterwards.
+ */
+static unsigned int gic_find_unused_lr(struct vcpu *v,
+                                       struct pending_irq *p,
+                                       unsigned int lr)
+{
+    unsigned int nr_lrs = gic_hw_ops->info->nr_lrs;
+    unsigned long *lr_mask = (unsigned long *) &this_cpu(lr_mask);
+    struct gic_lr lr_val;
+
+    ASSERT(spin_is_locked(&v->arch.vgic.lock));
+
+    if ( unlikely(test_bit(GIC_IRQ_GUEST_PRISTINE_LPI, &p->status)) )
+    {
+        unsigned int used_lr;
+
+        for_each_set_bit(used_lr, lr_mask, nr_lrs)
+        {
+            gic_hw_ops->read_lr(used_lr, &lr_val);
+            if ( lr_val.virq == p->irq )
+                return used_lr;
+        }
+    }
+
+    lr = find_next_zero_bit(lr_mask, nr_lrs, lr);
+
+    return lr;
+}
+
 void gic_raise_guest_irq(struct vcpu *v, unsigned int virtual_irq,
         unsigned int priority)
 {
@@ -455,7 +491,8 @@ void gic_raise_guest_irq(struct vcpu *v, unsigned int virtual_irq,
 
     if ( v == current && list_empty(&v->arch.vgic.lr_pending) )
     {
-        i = find_first_zero_bit(&this_cpu(lr_mask), nr_lrs);
+        i = gic_find_unused_lr(v, p, 0);
+
         if (i < nr_lrs) {
             set_bit(i, &this_cpu(lr_mask));
             gic_set_lr(i, p, GICH_LR_PENDING);
@@ -478,8 +515,14 @@ static void gic_update_one_lr(struct vcpu *v, int i)
     gic_hw_ops->read_lr(i, &lr_val);
     irq = lr_val.virq;
     p = irq_to_pending(v, irq);
-    /* An LPI might have been unmapped, in which case we just clean up here. */
-    if ( unlikely(!p) )
+    /*
+     * An LPI might have been unmapped, in which case we just clean up here.
+     * If that LPI is marked as PRISTINE, the information in the LR is bogus,
+     * as it belongs to a previous, already unmapped LPI. So we discard it
+     * here as well.
+     */
+    if ( unlikely(!p ||
+         test_and_clear_bit(GIC_IRQ_GUEST_PRISTINE_LPI, &p->status)) )
     {
         ASSERT(is_lpi(irq));
 
@@ -589,7 +632,7 @@ static void gic_restore_pending_irqs(struct vcpu *v)
     inflight_r = &v->arch.vgic.inflight_irqs;
     list_for_each_entry_safe ( p, t, &v->arch.vgic.lr_pending, lr_queue )
     {
-        lr = find_next_zero_bit(&this_cpu(lr_mask), nr_lrs, lr);
+        lr = gic_find_unused_lr(v, p, lr);
         if ( lr >= nr_lrs )
         {
             /* No more free LRs: find a lower priority irq to evict */
diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h
index 02732db..3fc4ceb 100644
--- a/xen/include/asm-arm/vgic.h
+++ b/xen/include/asm-arm/vgic.h
@@ -60,12 +60,18 @@ struct pending_irq
      * vcpu while it is still inflight and on an GICH_LR register on the
      * old vcpu.
      *
+     * GIC_IRQ_GUEST_PRISTINE_LPI: the IRQ is a newly mapped LPI, which
+     * has never been in an LR before. This means that any trace of an
+     * LPI with the same number in an LR must be from an older LPI, which
+     * has been unmapped before.
+     *
      */
 #define GIC_IRQ_GUEST_QUEUED   0
 #define GIC_IRQ_GUEST_ACTIVE   1
 #define GIC_IRQ_GUEST_VISIBLE  2
 #define GIC_IRQ_GUEST_ENABLED  3
 #define GIC_IRQ_GUEST_MIGRATING   4
+#define GIC_IRQ_GUEST_PRISTINE_LPI  5
     unsigned long status;
     struct irq_desc *desc; /* only set it the irq corresponds to a physical irq */
     unsigned int irq;
-- 
2.9.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* [PATCH v11 27/34] ARM: vITS: handle MAPTI/MAPI command
  2017-06-09 17:41 [PATCH v11 00/34] arm64: Dom0 ITS emulation Andre Przywara
                   ` (25 preceding siblings ...)
  2017-06-09 17:41 ` [PATCH v11 26/34] ARM: GICv3: handle unmapped LPIs Andre Przywara
@ 2017-06-09 17:41 ` Andre Przywara
  2017-06-12 16:36   ` Julien Grall
  2017-06-09 17:41 ` [PATCH v11 28/34] ARM: vITS: handle MOVI command Andre Przywara
                   ` (7 subsequent siblings)
  34 siblings, 1 reply; 71+ messages in thread
From: Andre Przywara @ 2017-06-09 17:41 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

The MAPTI commands associates a DeviceID/EventID pair with a LPI/CPU
pair and actually instantiates LPI interrupts. MAPI is just a variant
of this comment, where the LPI ID is the same as the event ID.
We connect the already allocated host LPI to this virtual LPI, so that
any triggering LPI on the host can be quickly forwarded to a guest.
Beside entering the domain and the virtual LPI number in the respective
host LPI entry, we also initialize and add the already allocated
struct pending_irq to our radix tree, so that we can now easily find it
by its virtual LPI number.
We also read the property table to update the enabled bit and the
priority for our new LPI, as we might have missed this during an earlier
INVALL call (which only checks mapped LPIs). But we make sure that the
property table is actually valid, as all redistributors might still
be disabled at this point.
Since write_itte_locked() now sees its first usage, we change the
declaration to static.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 xen/arch/arm/gic-v3-its.c        |  27 ++++++++
 xen/arch/arm/vgic-v3-its.c       | 145 ++++++++++++++++++++++++++++++++++++++-
 xen/include/asm-arm/gic_v3_its.h |   3 +
 3 files changed, 173 insertions(+), 2 deletions(-)

diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
index 8864e0b..3d863cd 100644
--- a/xen/arch/arm/gic-v3-its.c
+++ b/xen/arch/arm/gic-v3-its.c
@@ -876,6 +876,33 @@ int gicv3_remove_guest_event(struct domain *d, paddr_t vdoorbell_address,
     return 0;
 }
 
+/*
+ * Connects the event ID for an already assigned device to the given VCPU/vLPI
+ * pair. The corresponding physical LPI is already mapped on the host side
+ * (when assigning the physical device to the guest), so we just connect the
+ * target VCPU/vLPI pair to that interrupt to inject it properly if it fires.
+ * Returns a pointer to the already allocated struct pending_irq that is
+ * meant to be used by that event.
+ */
+struct pending_irq *gicv3_assign_guest_event(struct domain *d,
+                                             paddr_t vdoorbell_address,
+                                             uint32_t vdevid, uint32_t eventid,
+                                             uint32_t virt_lpi)
+{
+    struct pending_irq *pirq;
+    uint32_t host_lpi = INVALID_LPI;
+
+    pirq = get_event_pending_irq(d, vdoorbell_address, vdevid, eventid,
+                                 &host_lpi);
+
+    if ( !pirq )
+        return NULL;
+
+    gicv3_lpi_update_host_entry(host_lpi, d->domain_id, virt_lpi);
+
+    return pirq;
+}
+
 /* Scan the DT for any ITS nodes and create a list of host ITSes out of it. */
 void gicv3_its_dt_init(const struct dt_device_node *node)
 {
diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
index 7d4e55c..ada3040 100644
--- a/xen/arch/arm/vgic-v3-its.c
+++ b/xen/arch/arm/vgic-v3-its.c
@@ -253,8 +253,8 @@ static bool read_itte(struct virt_its *its, uint32_t devid, uint32_t evid,
  * If vcpu_ptr is provided, returns the VCPU belonging to that collection.
  * Must be called with the ITS lock held.
  */
-bool write_itte(struct virt_its *its, uint32_t devid,
-                uint32_t evid, uint32_t collid, uint32_t vlpi)
+static bool write_itte(struct virt_its *its, uint32_t devid,
+                       uint32_t evid, uint32_t collid, uint32_t vlpi)
 {
     paddr_t addr;
     struct vits_itte itte;
@@ -390,6 +390,44 @@ out_unlock:
     return ret;
 }
 
+/*
+ * For a given virtual LPI read the enabled bit and priority from the virtual
+ * property table and update the virtual IRQ's state in the given pending_irq.
+ * Must be called with the respective VGIC VCPU lock held.
+ */
+static int update_lpi_property(struct domain *d, struct pending_irq *p)
+{
+    paddr_t addr;
+    uint8_t property;
+    int ret;
+
+    /*
+     * If no redistributor has its LPIs enabled yet, we can't access the
+     * property table. In this case we just can't update the properties,
+     * but this should not be an error from an ITS point of view.
+     * The control flow dependency here and a barrier instruction on the
+     * write side make sure we can access these without taking a lock.
+     */
+    if ( !d->arch.vgic.rdists_enabled )
+        return 0;
+
+    addr = d->arch.vgic.rdist_propbase & GENMASK(51, 12);
+
+    ret = vgic_access_guest_memory(d, addr + p->irq - LPI_OFFSET,
+                                   &property, sizeof(property), false);
+    if ( ret )
+        return ret;
+
+    write_atomic(&p->lpi_priority, property & LPI_PROP_PRIO_MASK);
+
+    if ( property & LPI_PROP_ENABLED )
+        set_bit(GIC_IRQ_GUEST_ENABLED, &p->status);
+    else
+        clear_bit(GIC_IRQ_GUEST_ENABLED, &p->status);
+
+    return 0;
+}
+
 /* Must be called with the ITS lock held. */
 static int its_discard_event(struct virt_its *its,
                              uint32_t vdevid, uint32_t vevid)
@@ -515,6 +553,105 @@ static int its_handle_mapd(struct virt_its *its, uint64_t *cmdptr)
     return ret;
 }
 
+static int its_handle_mapti(struct virt_its *its, uint64_t *cmdptr)
+{
+    uint32_t devid = its_cmd_get_deviceid(cmdptr);
+    uint32_t eventid = its_cmd_get_id(cmdptr);
+    uint32_t intid = its_cmd_get_physical_id(cmdptr), _intid;
+    uint16_t collid = its_cmd_get_collection(cmdptr);
+    struct pending_irq *pirq;
+    struct vcpu *vcpu = NULL;
+    int ret = -1;
+
+    if ( its_cmd_get_command(cmdptr) == GITS_CMD_MAPI )
+        intid = eventid;
+
+    spin_lock(&its->its_lock);
+    /*
+     * Check whether there is a valid existing mapping. If yes, behavior is
+     * unpredictable, we choose to ignore this command here.
+     * This makes sure we start with a pristine pending_irq below.
+     */
+    if ( read_itte(its, devid, eventid, &vcpu, &_intid) &&
+         _intid != INVALID_LPI )
+    {
+        spin_unlock(&its->its_lock);
+        return -1;
+    }
+
+    /* Sanitize collection ID and interrupt ID */
+    vcpu = get_vcpu_from_collection(its, collid);
+    if ( !vcpu || intid >= its->d->arch.vgic.nr_lpis )
+    {
+        spin_unlock(&its->its_lock);
+        return -1;
+    }
+
+    /* Enter the mapping in our virtual ITS tables. */
+    if ( !write_itte(its, devid, eventid, collid, intid) )
+    {
+        spin_unlock(&its->its_lock);
+        return -1;
+    }
+
+    spin_unlock(&its->its_lock);
+
+    /*
+     * Connect this virtual LPI to the corresponding host LPI, which is
+     * determined by the same device ID and event ID on the host side.
+     * This returns us the corresponding, still unused pending_irq.
+     */
+    pirq = gicv3_assign_guest_event(its->d, its->doorbell_address,
+                                    devid, eventid, intid);
+    if ( !pirq )
+        goto out_remove_mapping;
+
+    vgic_init_pending_irq(pirq, intid);
+
+    /*
+     * Now read the guest's property table to initialize our cached state.
+     * We don't need the VGIC VCPU lock here, because the pending_irq isn't
+     * in the radix tree yet.
+     */
+    ret = update_lpi_property(its->d, pirq);
+    if ( ret )
+        goto out_remove_host_entry;
+
+    pirq->lpi_vcpu_id = vcpu->vcpu_id;
+    /*
+     * Mark this LPI as new, so any older (now unmapped) LPI in any LR
+     * can be easily recognised as such.
+     */
+    set_bit(GIC_IRQ_GUEST_PRISTINE_LPI, &pirq->status);
+
+    /*
+     * Now insert the pending_irq into the domain's LPI tree, so that
+     * it becomes live.
+     */
+    write_lock(&its->d->arch.vgic.pend_lpi_tree_lock);
+    ret = radix_tree_insert(&its->d->arch.vgic.pend_lpi_tree, intid, pirq);
+    write_unlock(&its->d->arch.vgic.pend_lpi_tree_lock);
+
+    if ( !ret )
+        return 0;
+
+    /*
+     * radix_tree_insert() returns an error either due to an internal
+     * condition (like memory allocation failure) or because the LPI already
+     * existed in the tree. We don't support the latter case, so we always
+     * cleanup and return an error here in any case.
+     */
+out_remove_host_entry:
+    gicv3_remove_guest_event(its->d, its->doorbell_address, devid, eventid);
+
+out_remove_mapping:
+    spin_lock(&its->its_lock);
+    write_itte(its, devid, eventid, UNMAPPED_COLLECTION, INVALID_LPI);
+    spin_unlock(&its->its_lock);
+
+    return ret;
+}
+
 #define ITS_CMD_BUFFER_SIZE(baser)      ((((baser) & 0xff) + 1) << 12)
 #define ITS_CMD_OFFSET(reg)             ((reg) & GENMASK(19, 5))
 
@@ -563,6 +700,10 @@ static int vgic_its_handle_cmds(struct domain *d, struct virt_its *its)
         case GITS_CMD_MAPD:
             ret = its_handle_mapd(its, command);
             break;
+        case GITS_CMD_MAPI:
+        case GITS_CMD_MAPTI:
+            ret = its_handle_mapti(its, command);
+            break;
         case GITS_CMD_SYNC:
             /* We handle ITS commands synchronously, so we ignore SYNC. */
             break;
diff --git a/xen/include/asm-arm/gic_v3_its.h b/xen/include/asm-arm/gic_v3_its.h
index 0089ac2..ce46a3f 100644
--- a/xen/include/asm-arm/gic_v3_its.h
+++ b/xen/include/asm-arm/gic_v3_its.h
@@ -177,6 +177,9 @@ struct pending_irq *gicv3_its_get_event_pending_irq(struct domain *d,
                                                     uint32_t eventid);
 int gicv3_remove_guest_event(struct domain *d, paddr_t vdoorbell_address,
                                      uint32_t vdevid, uint32_t eventid);
+struct pending_irq *gicv3_assign_guest_event(struct domain *d, paddr_t doorbell,
+                                             uint32_t devid, uint32_t eventid,
+                                             uint32_t virt_lpi);
 void gicv3_lpi_update_host_entry(uint32_t host_lpi, int domain_id,
                                  uint32_t virt_lpi);
 
-- 
2.9.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* [PATCH v11 28/34] ARM: vITS: handle MOVI command
  2017-06-09 17:41 [PATCH v11 00/34] arm64: Dom0 ITS emulation Andre Przywara
                   ` (26 preceding siblings ...)
  2017-06-09 17:41 ` [PATCH v11 27/34] ARM: vITS: handle MAPTI/MAPI command Andre Przywara
@ 2017-06-09 17:41 ` Andre Przywara
  2017-06-12 16:37   ` Julien Grall
  2017-06-09 17:41 ` [PATCH v11 29/34] ARM: vITS: handle DISCARD command Andre Przywara
                   ` (6 subsequent siblings)
  34 siblings, 1 reply; 71+ messages in thread
From: Andre Przywara @ 2017-06-09 17:41 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

The MOVI command moves the interrupt affinity from one redistributor
(read: VCPU) to another.
For now migration of "live" LPIs is not yet implemented, but we store
the changed affinity in our virtual ITTE and the pending_irq.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 xen/arch/arm/vgic-v3-its.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 69 insertions(+)

diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
index ada3040..49969e4 100644
--- a/xen/arch/arm/vgic-v3-its.c
+++ b/xen/arch/arm/vgic-v3-its.c
@@ -652,6 +652,69 @@ out_remove_mapping:
     return ret;
 }
 
+static int its_handle_movi(struct virt_its *its, uint64_t *cmdptr)
+{
+    uint32_t devid = its_cmd_get_deviceid(cmdptr);
+    uint32_t eventid = its_cmd_get_id(cmdptr);
+    uint16_t collid = its_cmd_get_collection(cmdptr);
+    unsigned long flags;
+    struct pending_irq *p;
+    struct vcpu *ovcpu, *nvcpu;
+    uint32_t vlpi;
+    int ret = -1;
+
+    spin_lock(&its->its_lock);
+    /* Check for a mapped LPI and get the LPI number. */
+    if ( !read_itte(its, devid, eventid, &ovcpu, &vlpi) )
+        goto out_unlock;
+
+    if ( vlpi == INVALID_LPI )
+        goto out_unlock;
+
+    /* Check the new collection ID and get the new VCPU pointer */
+    nvcpu = get_vcpu_from_collection(its, collid);
+    if ( !nvcpu )
+        goto out_unlock;
+
+    p = gicv3_its_get_event_pending_irq(its->d, its->doorbell_address,
+                                        devid, eventid);
+    if ( unlikely(!p) )
+        goto out_unlock;
+
+    /*
+     * TODO: This relies on the VCPU being correct in the ITS tables.
+     * This can be fixed by either using a per-IRQ lock or by using
+     * the VCPU ID from the pending_irq instead.
+     */
+    spin_lock_irqsave(&ovcpu->arch.vgic.lock, flags);
+
+    /* Update our cached vcpu_id in the pending_irq. */
+    p->lpi_vcpu_id = nvcpu->vcpu_id;
+
+    spin_unlock_irqrestore(&ovcpu->arch.vgic.lock, flags);
+
+    /*
+     * TODO: Investigate if and how to migrate an already pending LPI. This
+     * is not really critical, as these benign races happen in hardware too
+     * (an affinity change may come too late for a just fired IRQ), but may
+     * simplify the code if we can keep the IRQ's associated VCPU in sync,
+     * so that we don't have to deal with special cases anymore.
+     * Migrating those LPIs is not easy to do at the moment anyway, but should
+     * become easier with the introduction of a per-IRQ lock.
+     */
+
+    /* Now store the new collection in the translation table. */
+    if ( !write_itte(its, devid, eventid, collid, vlpi) )
+        goto out_unlock;
+
+    ret = 0;
+
+out_unlock:
+    spin_unlock(&its->its_lock);
+
+    return ret;
+}
+
 #define ITS_CMD_BUFFER_SIZE(baser)      ((((baser) & 0xff) + 1) << 12)
 #define ITS_CMD_OFFSET(reg)             ((reg) & GENMASK(19, 5))
 
@@ -704,6 +767,12 @@ static int vgic_its_handle_cmds(struct domain *d, struct virt_its *its)
         case GITS_CMD_MAPTI:
             ret = its_handle_mapti(its, command);
             break;
+        case GITS_CMD_MOVALL:
+            gdprintk(XENLOG_G_INFO, "vGITS: ignoring MOVALL command\n");
+            break;
+        case GITS_CMD_MOVI:
+            ret = its_handle_movi(its, command);
+            break;
         case GITS_CMD_SYNC:
             /* We handle ITS commands synchronously, so we ignore SYNC. */
             break;
-- 
2.9.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* [PATCH v11 29/34] ARM: vITS: handle DISCARD command
  2017-06-09 17:41 [PATCH v11 00/34] arm64: Dom0 ITS emulation Andre Przywara
                   ` (27 preceding siblings ...)
  2017-06-09 17:41 ` [PATCH v11 28/34] ARM: vITS: handle MOVI command Andre Przywara
@ 2017-06-09 17:41 ` Andre Przywara
  2017-06-09 17:41 ` [PATCH v11 30/34] ARM: vITS: handle INV command Andre Przywara
                   ` (5 subsequent siblings)
  34 siblings, 0 replies; 71+ messages in thread
From: Andre Przywara @ 2017-06-09 17:41 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

The DISCARD command drops the connection between a DeviceID/EventID
and an LPI/collection pair.
We mark the respective structure entries as not allocated and make
sure that any queued IRQs are removed.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Acked-by: Julien Grall <julien.grall@arm.com>
---
 xen/arch/arm/vgic-v3-its.c | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
index 49969e4..7d2bb30 100644
--- a/xen/arch/arm/vgic-v3-its.c
+++ b/xen/arch/arm/vgic-v3-its.c
@@ -715,6 +715,29 @@ out_unlock:
     return ret;
 }
 
+static int its_handle_discard(struct virt_its *its, uint64_t *cmdptr)
+{
+    uint32_t devid = its_cmd_get_deviceid(cmdptr);
+    uint32_t eventid = its_cmd_get_id(cmdptr);
+    int ret;
+
+    spin_lock(&its->its_lock);
+
+    /* Remove from the radix tree and remove the host entry. */
+    ret = its_discard_event(its, devid, eventid);
+    if ( ret )
+        goto out_unlock;
+
+    /* Remove from the guest's ITTE. */
+    if ( !write_itte(its, devid, eventid, UNMAPPED_COLLECTION, INVALID_LPI) )
+        ret = -1;
+
+out_unlock:
+    spin_unlock(&its->its_lock);
+
+    return ret;
+}
+
 #define ITS_CMD_BUFFER_SIZE(baser)      ((((baser) & 0xff) + 1) << 12)
 #define ITS_CMD_OFFSET(reg)             ((reg) & GENMASK(19, 5))
 
@@ -754,6 +777,9 @@ static int vgic_its_handle_cmds(struct domain *d, struct virt_its *its)
         case GITS_CMD_CLEAR:
             ret = its_handle_clear(its, command);
             break;
+        case GITS_CMD_DISCARD:
+            ret = its_handle_discard(its, command);
+            break;
         case GITS_CMD_INT:
             ret = its_handle_int(its, command);
             break;
-- 
2.9.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* [PATCH v11 30/34] ARM: vITS: handle INV command
  2017-06-09 17:41 [PATCH v11 00/34] arm64: Dom0 ITS emulation Andre Przywara
                   ` (28 preceding siblings ...)
  2017-06-09 17:41 ` [PATCH v11 29/34] ARM: vITS: handle DISCARD command Andre Przywara
@ 2017-06-09 17:41 ` Andre Przywara
  2017-06-09 17:41 ` [PATCH v11 31/34] ARM: vITS: handle INVALL command Andre Przywara
                   ` (4 subsequent siblings)
  34 siblings, 0 replies; 71+ messages in thread
From: Andre Przywara @ 2017-06-09 17:41 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

The INV command instructs the ITS to update the configuration data for
a given LPI by re-reading its entry from the property table.
We don't need to care so much about the priority value, but enabling
or disabling an LPI has some effect: We remove or push virtual LPIs
to their VCPUs, also check the virtual pending bit if an LPI gets enabled.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Reviewed-by: Stefano Stabellini <sstabellini@kernel.org>
---
 xen/arch/arm/vgic-v3-its.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 79 insertions(+)

diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
index 7d2bb30..d0d64c7 100644
--- a/xen/arch/arm/vgic-v3-its.c
+++ b/xen/arch/arm/vgic-v3-its.c
@@ -428,6 +428,82 @@ static int update_lpi_property(struct domain *d, struct pending_irq *p)
     return 0;
 }
 
+/*
+ * Checks whether an LPI that got enabled or disabled needs to change
+ * something in the VGIC (added or removed from the LR or queues).
+ * We don't disable the underlying physical LPI, because this requires
+ * queueing a host LPI command, which we can't afford to do on behalf
+ * of a guest.
+ * Must be called with the VCPU VGIC lock held.
+ */
+static void update_lpi_vgic_status(struct vcpu *v, struct pending_irq *p)
+{
+    ASSERT(spin_is_locked(&v->arch.vgic.lock));
+
+    if ( test_bit(GIC_IRQ_GUEST_ENABLED, &p->status) )
+    {
+        if ( !list_empty(&p->inflight) &&
+             !test_bit(GIC_IRQ_GUEST_VISIBLE, &p->status) )
+            gic_raise_guest_irq(v, p->irq, p->lpi_priority);
+    }
+    else
+        gic_remove_from_lr_pending(v, p);
+}
+
+static int its_handle_inv(struct virt_its *its, uint64_t *cmdptr)
+{
+    struct domain *d = its->d;
+    uint32_t devid = its_cmd_get_deviceid(cmdptr);
+    uint32_t eventid = its_cmd_get_id(cmdptr);
+    struct pending_irq *p;
+    unsigned long flags;
+    struct vcpu *vcpu;
+    uint32_t vlpi;
+    int ret = -1;
+
+    /*
+     * If no redistributor has its LPIs enabled yet, we can't access the
+     * property table, so there is no point in executing this command.
+     * The control flow dependency here and a barrier instruction on the
+     * write side make sure we can access these without taking a lock.
+     */
+    if ( !d->arch.vgic.rdists_enabled )
+        return 0;
+
+    spin_lock(&its->its_lock);
+
+    /* Translate the event into a vCPU/vLPI pair. */
+    if ( !read_itte(its, devid, eventid, &vcpu, &vlpi) )
+        goto out_unlock_its;
+
+    if ( vlpi == INVALID_LPI )
+        goto out_unlock_its;
+
+    p = gicv3_its_get_event_pending_irq(d, its->doorbell_address,
+                                        devid, eventid);
+    if ( unlikely(!p) )
+        goto out_unlock_its;
+
+    spin_lock_irqsave(&vcpu->arch.vgic.lock, flags);
+
+    /* Read the property table and update our cached status. */
+    if ( update_lpi_property(d, p) )
+        goto out_unlock;
+
+    /* Check whether the LPI needs to go on a VCPU. */
+    update_lpi_vgic_status(vcpu, p);
+
+    ret = 0;
+
+out_unlock:
+    spin_unlock_irqrestore(&vcpu->arch.vgic.lock, flags);
+
+out_unlock_its:
+    spin_unlock(&its->its_lock);
+
+    return ret;
+}
+
 /* Must be called with the ITS lock held. */
 static int its_discard_event(struct virt_its *its,
                              uint32_t vdevid, uint32_t vevid)
@@ -783,6 +859,9 @@ static int vgic_its_handle_cmds(struct domain *d, struct virt_its *its)
         case GITS_CMD_INT:
             ret = its_handle_int(its, command);
             break;
+        case GITS_CMD_INV:
+            ret = its_handle_inv(its, command);
+            break;
         case GITS_CMD_MAPC:
             ret = its_handle_mapc(its, command);
             break;
-- 
2.9.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* [PATCH v11 31/34] ARM: vITS: handle INVALL command
  2017-06-09 17:41 [PATCH v11 00/34] arm64: Dom0 ITS emulation Andre Przywara
                   ` (29 preceding siblings ...)
  2017-06-09 17:41 ` [PATCH v11 30/34] ARM: vITS: handle INV command Andre Przywara
@ 2017-06-09 17:41 ` Andre Przywara
  2017-06-12 16:41   ` Julien Grall
  2017-06-09 17:41 ` [PATCH v11 32/34] ARM: vITS: increase mmio_count for each ITS Andre Przywara
                   ` (3 subsequent siblings)
  34 siblings, 1 reply; 71+ messages in thread
From: Andre Przywara @ 2017-06-09 17:41 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

The INVALL command instructs an ITS to invalidate the configuration
data for all LPIs associated with a given redistributor (read: VCPU).
This is nasty to emulate exactly with our architecture, so we just
iterate over all mapped LPIs and filter for those from that particular
VCPU.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 xen/arch/arm/vgic-v3-its.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 79 insertions(+)

diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
index d0d64c7..d3e0324 100644
--- a/xen/arch/arm/vgic-v3-its.c
+++ b/xen/arch/arm/vgic-v3-its.c
@@ -504,6 +504,82 @@ out_unlock_its:
     return ret;
 }
 
+/*
+ * INVALL updates the per-LPI configuration status for every LPI mapped to
+ * a particular redistributor.
+ * We iterate over all mapped LPIs in our radix tree and update those.
+ */
+static int its_handle_invall(struct virt_its *its, uint64_t *cmdptr)
+{
+    uint32_t collid = its_cmd_get_collection(cmdptr);
+    struct vcpu *vcpu;
+    struct pending_irq *pirqs[16];
+    uint64_t vlpi = 0;          /* 64-bit to catch overflows */
+    unsigned int nr_lpis, i;
+    unsigned long flags;
+    int ret = 0;
+
+    /*
+     * As this implementation walks over all mapped LPIs, it might take
+     * too long for a real guest, so we might want to revisit this
+     * implementation for DomUs.
+     * However this command is very rare, also we don't expect many
+     * LPIs to be actually mapped, so it's fine for Dom0 to use.
+     */
+    ASSERT(is_hardware_domain(its->d));
+
+    /*
+     * If no redistributor has its LPIs enabled yet, we can't access the
+     * property table, so there is no point in executing this command.
+     * The control flow dependency here and a barrier instruction on the
+     * write side make sure we can access these without taking a lock.
+     */
+    if ( !its->d->arch.vgic.rdists_enabled )
+        return 0;
+
+    spin_lock(&its->its_lock);
+    vcpu = get_vcpu_from_collection(its, collid);
+    spin_unlock(&its->its_lock);
+
+    spin_lock_irqsave(&vcpu->arch.vgic.lock, flags);
+    read_lock(&its->d->arch.vgic.pend_lpi_tree_lock);
+
+    do
+    {
+        int err;
+
+        nr_lpis = radix_tree_gang_lookup(&its->d->arch.vgic.pend_lpi_tree,
+                                         (void **)pirqs, vlpi,
+                                         ARRAY_SIZE(pirqs));
+
+        for ( i = 0; i < nr_lpis; i++ )
+        {
+            /* We only care about LPIs on our VCPU. */
+            if ( pirqs[i]->lpi_vcpu_id != vcpu->vcpu_id )
+                continue;
+
+            vlpi = pirqs[i]->irq;
+            /* If that fails for a single LPI, carry on to handle the rest. */
+            err = update_lpi_property(its->d, pirqs[i]);
+            if ( !err )
+                update_lpi_vgic_status(vcpu, pirqs[i]);
+            else
+                ret = err;
+        }
+    /*
+     * Loop over the next gang of pending_irqs until we reached the end of
+     * a (fully populated) tree or the lookup function returns less LPIs than
+     * it has been asked for.
+     */
+    } while ( (++vlpi < its->d->arch.vgic.nr_lpis) &&
+              (nr_lpis == ARRAY_SIZE(pirqs)) );
+
+    read_unlock(&its->d->arch.vgic.pend_lpi_tree_lock);
+    spin_unlock_irqrestore(&vcpu->arch.vgic.lock, flags);
+
+    return ret;
+}
+
 /* Must be called with the ITS lock held. */
 static int its_discard_event(struct virt_its *its,
                              uint32_t vdevid, uint32_t vevid)
@@ -862,6 +938,9 @@ static int vgic_its_handle_cmds(struct domain *d, struct virt_its *its)
         case GITS_CMD_INV:
             ret = its_handle_inv(its, command);
             break;
+        case GITS_CMD_INVALL:
+            ret = its_handle_invall(its, command);
+            break;
         case GITS_CMD_MAPC:
             ret = its_handle_mapc(its, command);
             break;
-- 
2.9.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* [PATCH v11 32/34] ARM: vITS: increase mmio_count for each ITS
  2017-06-09 17:41 [PATCH v11 00/34] arm64: Dom0 ITS emulation Andre Przywara
                   ` (30 preceding siblings ...)
  2017-06-09 17:41 ` [PATCH v11 31/34] ARM: vITS: handle INVALL command Andre Przywara
@ 2017-06-09 17:41 ` Andre Przywara
  2017-06-09 17:41 ` [PATCH v11 33/34] ARM: vITS: create and initialize virtual ITSes for Dom0 Andre Przywara
                   ` (2 subsequent siblings)
  34 siblings, 0 replies; 71+ messages in thread
From: Andre Przywara @ 2017-06-09 17:41 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

Increase the count of MMIO regions needed by one for each ITS Dom0 has
to emulate. We emulate the ITSes 1:1 from the hardware, so the number
is the number of host ITSes.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Acked-by: Julien Grall <julien.grall@arm.com>
---
 xen/arch/arm/vgic-v3-its.c       | 15 +++++++++++++++
 xen/arch/arm/vgic-v3.c           |  3 +++
 xen/include/asm-arm/gic_v3_its.h |  7 +++++++
 3 files changed, 25 insertions(+)

diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
index d3e0324..4eef37e 100644
--- a/xen/arch/arm/vgic-v3-its.c
+++ b/xen/arch/arm/vgic-v3-its.c
@@ -1455,6 +1455,21 @@ static const struct mmio_handler_ops vgic_its_mmio_handler = {
     .write = vgic_v3_its_mmio_write,
 };
 
+unsigned int vgic_v3_its_count(const struct domain *d)
+{
+    struct host_its *hw_its;
+    unsigned int ret = 0;
+
+    /* Only Dom0 can use emulated ITSes so far. */
+    if ( !is_hardware_domain(d) )
+        return 0;
+
+    list_for_each_entry(hw_its, &host_its_list, entry)
+        ret++;
+
+    return ret;
+}
+
 int vgic_v3_its_init_domain(struct domain *d)
 {
     spin_lock_init(&d->arch.vgic.its_devices_lock);
diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
index 296991a..cddb920 100644
--- a/xen/arch/arm/vgic-v3.c
+++ b/xen/arch/arm/vgic-v3.c
@@ -1814,6 +1814,9 @@ int vgic_v3_init(struct domain *d, int *mmio_count)
     /* GICD region + number of Redistributors */
     *mmio_count = vgic_v3_rdist_count(d) + 1;
 
+    /* one region per ITS */
+    *mmio_count += vgic_v3_its_count(d);
+
     register_vgic_ops(d, &v3_ops);
 
     return 0;
diff --git a/xen/include/asm-arm/gic_v3_its.h b/xen/include/asm-arm/gic_v3_its.h
index ce46a3f..459b6fe 100644
--- a/xen/include/asm-arm/gic_v3_its.h
+++ b/xen/include/asm-arm/gic_v3_its.h
@@ -137,6 +137,8 @@ void gicv3_its_dt_init(const struct dt_device_node *node);
 
 bool gicv3_its_host_has_its(void);
 
+unsigned int vgic_v3_its_count(const struct domain *d);
+
 void gicv3_do_LPI(unsigned int lpi);
 
 int gicv3_lpi_init_rdist(void __iomem * rdist_base);
@@ -194,6 +196,11 @@ static inline bool gicv3_its_host_has_its(void)
     return false;
 }
 
+static inline unsigned int vgic_v3_its_count(const struct domain *d)
+{
+    return 0;
+}
+
 static inline void gicv3_do_LPI(unsigned int lpi)
 {
     /* We don't enable LPIs without an ITS. */
-- 
2.9.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* [PATCH v11 33/34] ARM: vITS: create and initialize virtual ITSes for Dom0
  2017-06-09 17:41 [PATCH v11 00/34] arm64: Dom0 ITS emulation Andre Przywara
                   ` (31 preceding siblings ...)
  2017-06-09 17:41 ` [PATCH v11 32/34] ARM: vITS: increase mmio_count for each ITS Andre Przywara
@ 2017-06-09 17:41 ` Andre Przywara
  2017-06-09 17:41 ` [PATCH v11 34/34] ARM: vITS: create ITS subnodes for Dom0 DT Andre Przywara
  2017-06-12  5:04 ` [PATCH v11 00/34] arm64: Dom0 ITS emulation Manish Jaggi
  34 siblings, 0 replies; 71+ messages in thread
From: Andre Przywara @ 2017-06-09 17:41 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

For each hardware ITS create and initialize a virtual ITS for Dom0.
We use the same memory mapped address to keep the doorbell working.
This introduces a function to initialize a virtual ITS.
We maintain a list of virtual ITSes, at the moment for the only
purpose of later being able to free them again.
We configure the virtual ITSes to match the hardware ones, that is we
keep the number of device ID bits and event ID bits the same as the host
ITS.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Acked-by: Julien Grall <julien.grall@arm.com>
---
 xen/arch/arm/vgic-v3-its.c   | 77 ++++++++++++++++++++++++++++++++++++++++++++
 xen/include/asm-arm/domain.h |  1 +
 2 files changed, 78 insertions(+)

diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
index 4eef37e..ddc00b7 100644
--- a/xen/arch/arm/vgic-v3-its.c
+++ b/xen/arch/arm/vgic-v3-its.c
@@ -52,6 +52,7 @@
  */
 struct virt_its {
     struct domain *d;
+    struct list_head vits_list;
     paddr_t doorbell_address;
     unsigned int devid_bits;
     unsigned int evid_bits;
@@ -1455,6 +1456,46 @@ static const struct mmio_handler_ops vgic_its_mmio_handler = {
     .write = vgic_v3_its_mmio_write,
 };
 
+static int vgic_v3_its_init_virtual(struct domain *d, paddr_t guest_addr,
+                                    unsigned int devid_bits,
+                                    unsigned int evid_bits)
+{
+    struct virt_its *its;
+    uint64_t base_attr;
+
+    its = xzalloc(struct virt_its);
+    if ( !its )
+        return -ENOMEM;
+
+    base_attr  = GIC_BASER_InnerShareable << GITS_BASER_SHAREABILITY_SHIFT;
+    base_attr |= GIC_BASER_CACHE_SameAsInner << GITS_BASER_OUTER_CACHEABILITY_SHIFT;
+    base_attr |= GIC_BASER_CACHE_RaWaWb << GITS_BASER_INNER_CACHEABILITY_SHIFT;
+
+    its->cbaser  = base_attr;
+    base_attr |= 0ULL << GITS_BASER_PAGE_SIZE_SHIFT;    /* 4K pages */
+    its->baser_dev = GITS_BASER_TYPE_DEVICE << GITS_BASER_TYPE_SHIFT;
+    its->baser_dev |= (sizeof(dev_table_entry_t) - 1) <<
+                      GITS_BASER_ENTRY_SIZE_SHIFT;
+    its->baser_dev |= base_attr;
+    its->baser_coll  = GITS_BASER_TYPE_COLLECTION << GITS_BASER_TYPE_SHIFT;
+    its->baser_coll |= (sizeof(coll_table_entry_t) - 1) <<
+                       GITS_BASER_ENTRY_SIZE_SHIFT;
+    its->baser_coll |= base_attr;
+    its->d = d;
+    its->doorbell_address = guest_addr + ITS_DOORBELL_OFFSET;
+    its->devid_bits = devid_bits;
+    its->evid_bits = evid_bits;
+    spin_lock_init(&its->vcmd_lock);
+    spin_lock_init(&its->its_lock);
+
+    register_mmio_handler(d, &vgic_its_mmio_handler, guest_addr, SZ_64K, its);
+
+    /* Register the virtual ITS to be able to clean it up later. */
+    list_add_tail(&its->vits_list, &d->arch.vgic.vits_list);
+
+    return 0;
+}
+
 unsigned int vgic_v3_its_count(const struct domain *d)
 {
     struct host_its *hw_its;
@@ -1470,16 +1511,52 @@ unsigned int vgic_v3_its_count(const struct domain *d)
     return ret;
 }
 
+/*
+ * For a hardware domain, this will iterate over the host ITSes
+ * and map one virtual ITS per host ITS at the same address.
+ */
 int vgic_v3_its_init_domain(struct domain *d)
 {
+    int ret;
+
+    INIT_LIST_HEAD(&d->arch.vgic.vits_list);
     spin_lock_init(&d->arch.vgic.its_devices_lock);
     d->arch.vgic.its_devices = RB_ROOT;
 
+    if ( is_hardware_domain(d) )
+    {
+        struct host_its *hw_its;
+
+        list_for_each_entry(hw_its, &host_its_list, entry)
+        {
+            /*
+             * For each host ITS create a virtual ITS using the same
+             * base and thus doorbell address.
+             * Use the same number of device ID and event ID bits as the host.
+             */
+            ret = vgic_v3_its_init_virtual(d, hw_its->addr,
+                                           hw_its->devid_bits,
+                                           hw_its->evid_bits);
+            if ( ret )
+                return ret;
+            else
+                d->arch.vgic.has_its = true;
+        }
+    }
+
     return 0;
 }
 
 void vgic_v3_its_free_domain(struct domain *d)
 {
+    struct virt_its *pos, *temp;
+
+    list_for_each_entry_safe( pos, temp, &d->arch.vgic.vits_list, vits_list )
+    {
+        list_del(&pos->vits_list);
+        xfree(pos);
+    }
+
     ASSERT(RB_EMPTY_ROOT(&d->arch.vgic.its_devices));
 }
 
diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
index b33f54a..8dfc1d1 100644
--- a/xen/include/asm-arm/domain.h
+++ b/xen/include/asm-arm/domain.h
@@ -115,6 +115,7 @@ struct arch_domain
         spinlock_t its_devices_lock;        /* Protects the its_devices tree */
         struct radix_tree_root pend_lpi_tree; /* Stores struct pending_irq's */
         rwlock_t pend_lpi_tree_lock;        /* Protects the pend_lpi_tree */
+        struct list_head vits_list;         /* List of virtual ITSes */
         unsigned int intid_bits;
         /*
          * TODO: if there are more bool's being added below, consider
-- 
2.9.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* [PATCH v11 34/34] ARM: vITS: create ITS subnodes for Dom0 DT
  2017-06-09 17:41 [PATCH v11 00/34] arm64: Dom0 ITS emulation Andre Przywara
                   ` (32 preceding siblings ...)
  2017-06-09 17:41 ` [PATCH v11 33/34] ARM: vITS: create and initialize virtual ITSes for Dom0 Andre Przywara
@ 2017-06-09 17:41 ` Andre Przywara
  2017-06-12  5:04 ` [PATCH v11 00/34] arm64: Dom0 ITS emulation Manish Jaggi
  34 siblings, 0 replies; 71+ messages in thread
From: Andre Przywara @ 2017-06-09 17:41 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

Dom0 expects all ITSes in the system to be propagated to be able to
use MSIs.
Create Dom0 DT nodes for each hardware ITS, keeping the register frame
address the same, as the doorbell address that the Dom0 drivers program
into the BARs has to match the hardware.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Acked-by: Julien Grall <julien.grall@arm.com>
---
 xen/arch/arm/gic-v3-its.c        | 73 ++++++++++++++++++++++++++++++++++++++++
 xen/arch/arm/gic-v3.c            |  4 ++-
 xen/include/asm-arm/gic_v3_its.h | 12 +++++++
 3 files changed, 88 insertions(+), 1 deletion(-)

diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
index 3d863cd..2d36030 100644
--- a/xen/arch/arm/gic-v3-its.c
+++ b/xen/arch/arm/gic-v3-its.c
@@ -20,6 +20,7 @@
 
 #include <xen/lib.h>
 #include <xen/delay.h>
+#include <xen/libfdt/libfdt.h>
 #include <xen/mm.h>
 #include <xen/rbtree.h>
 #include <xen/sched.h>
@@ -903,6 +904,78 @@ struct pending_irq *gicv3_assign_guest_event(struct domain *d,
     return pirq;
 }
 
+/*
+ * Create the respective guest DT nodes from a list of host ITSes.
+ * This copies the reg property, so the guest sees the ITS at the same address
+ * as the host.
+ */
+int gicv3_its_make_hwdom_dt_nodes(const struct domain *d,
+                                  const struct dt_device_node *gic,
+                                  void *fdt)
+{
+    uint32_t len;
+    int res;
+    const void *prop = NULL;
+    const struct dt_device_node *its = NULL;
+    const struct host_its *its_data;
+
+    if ( list_empty(&host_its_list) )
+        return 0;
+
+    /* The sub-nodes require the ranges property */
+    prop = dt_get_property(gic, "ranges", &len);
+    if ( !prop )
+    {
+        printk(XENLOG_ERR "Can't find ranges property for the gic node\n");
+        return -FDT_ERR_XEN(ENOENT);
+    }
+
+    res = fdt_property(fdt, "ranges", prop, len);
+    if ( res )
+        return res;
+
+    list_for_each_entry(its_data, &host_its_list, entry)
+    {
+        its = its_data->dt_node;
+
+        res = fdt_begin_node(fdt, its->name);
+        if ( res )
+            return res;
+
+        res = fdt_property_string(fdt, "compatible", "arm,gic-v3-its");
+        if ( res )
+            return res;
+
+        res = fdt_property(fdt, "msi-controller", NULL, 0);
+        if ( res )
+            return res;
+
+        if ( its->phandle )
+        {
+            res = fdt_property_cell(fdt, "phandle", its->phandle);
+            if ( res )
+                return res;
+        }
+
+        /* Use the same reg regions as the ITS node in host DTB. */
+        prop = dt_get_property(its, "reg", &len);
+        if ( !prop )
+        {
+            printk(XENLOG_ERR "GICv3: Can't find ITS reg property.\n");
+            res = -FDT_ERR_XEN(ENOENT);
+            return res;
+        }
+
+        res = fdt_property(fdt, "reg", prop, len);
+        if ( res )
+            return res;
+
+        fdt_end_node(fdt);
+    }
+
+    return res;
+}
+
 /* Scan the DT for any ITS nodes and create a list of host ITSes out of it. */
 void gicv3_its_dt_init(const struct dt_device_node *node)
 {
diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c
index d539d6c..c927306 100644
--- a/xen/arch/arm/gic-v3.c
+++ b/xen/arch/arm/gic-v3.c
@@ -1172,8 +1172,10 @@ static int gicv3_make_hwdom_dt_node(const struct domain *d,
 
     res = fdt_property(fdt, "reg", new_cells, len);
     xfree(new_cells);
+    if ( res )
+        return res;
 
-    return res;
+    return gicv3_its_make_hwdom_dt_nodes(d, gic, fdt);
 }
 
 static const hw_irq_controller gicv3_host_irq_type = {
diff --git a/xen/include/asm-arm/gic_v3_its.h b/xen/include/asm-arm/gic_v3_its.h
index 459b6fe..1fac1c7 100644
--- a/xen/include/asm-arm/gic_v3_its.h
+++ b/xen/include/asm-arm/gic_v3_its.h
@@ -158,6 +158,11 @@ int gicv3_its_setup_collection(unsigned int cpu);
 int vgic_v3_its_init_domain(struct domain *d);
 void vgic_v3_its_free_domain(struct domain *d);
 
+/* Create the appropriate DT nodes for a hardware domain. */
+int gicv3_its_make_hwdom_dt_nodes(const struct domain *d,
+                                  const struct dt_device_node *gic,
+                                  void *fdt);
+
 /*
  * Map a device on the host by allocating an ITT on the host (ITS).
  * "nr_event" specifies how many events (interrupts) this device will need.
@@ -242,6 +247,13 @@ static inline void vgic_v3_its_free_domain(struct domain *d)
 {
 }
 
+static inline int gicv3_its_make_hwdom_dt_nodes(const struct domain *d,
+                                                const struct dt_device_node *gic,
+                                                void *fdt)
+{
+    return 0;
+}
+
 #endif /* CONFIG_HAS_ITS */
 
 #endif
-- 
2.9.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* Re: [PATCH v11 00/34] arm64: Dom0 ITS emulation
  2017-06-09 17:41 [PATCH v11 00/34] arm64: Dom0 ITS emulation Andre Przywara
                   ` (33 preceding siblings ...)
  2017-06-09 17:41 ` [PATCH v11 34/34] ARM: vITS: create ITS subnodes for Dom0 DT Andre Przywara
@ 2017-06-12  5:04 ` Manish Jaggi
  34 siblings, 0 replies; 71+ messages in thread
From: Manish Jaggi @ 2017-06-12  5:04 UTC (permalink / raw)
  To: Andre Przywara, Julien Grall, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni



On 6/9/2017 11:11 PM, Andre Przywara wrote:
> Hi,
Hi Andre,
Tested this patchset + my acpi ITS patch 
(https://lists.xen.org/archives/html/xen-devel/2017-06/msg00716.html) on 
our platform and it works.
With v10 was not able to get interrupts. v9 was booting ok.

WBR
-Manish
> fixes to v10, with their number getting eventually smaller ;-)
> The same restriction as for the previous versions  still apply: the locking
> is considered somewhat insufficient and will be fixed by an upcoming rework.
>
> Patch 01/34 was reworked to properly synchronize access to the priority
> in a lock-less fashion. This should be back-ported to 4.9.
> The former patch 12/32 ("enable ITS and LPIs on the host") was moved up-front
> and split to allow back-porting the new 02/34 to Xen 4.9, which is broken
> if the preliminary ITS support is configured in and the machine advertises
> an ITS in the device tree.
>
> No big changes this time: some bugs fixed (many thanks to Julien for
> proper testing!), some extended comments and some improvements to better
> protect parallel accesses. For a detailed changelog see below.
>
> I added Acked-by: and Reviewed-by: tags, but refrained from doing so
> for Julien's tags for patch 18/34 and 20/34, since I changed them slightly.
>
> Cheers,
> Andre
>
> ----------------------------------
> This series adds support for emulation of an ARM GICv3 ITS interrupt
> controller. For hardware which relies on the ITS to provide interrupts for
> its peripherals this code is needed to get a machine booted into Dom0 at
> all. ITS emulation for DomUs is only really useful with PCI passthrough,
> which is not yet available for ARM. It is expected that this feature
> will be co-developed with the ITS DomU code. However this code drop here
> considered DomU emulation already, to keep later architectural changes
> to a minimum.
>
> This is technical preview version to allow early testing of the feature.
> Things not (properly) addressed in this release:
> - There is only support for Dom0 at the moment. DomU support is only really
> useful with PCI passthrough, which is not there yet for ARM.
> - The MOVALL command is not emulated. In our case there is really nothing
> to do here. We might need to revisit this in the future for DomU support.
> - The INVALL command might need some rework to be more efficient. Currently
> we iterate over all mapped LPIs, which might take a bit longer.
> - Indirect tables are not supported. This affects both the host and the
> virtual side.
> - The ITS tables inside (Dom0) guest memory cannot easily be protected
> at the moment (without restricting access to Xen as well). So for now
> we trust Dom0 not to touch this memory (which the spec forbids as well).
> - With malicious guests (DomUs) there is a possibility of an interrupt
> storm triggered by a device. We would need to investigate what that means
> for Xen and if there is a nice way to prevent this. Disabling the LPI on
> the host side would require command queuing, which has its downsides to
> be issued during runtime.
> - Dom0 should make sure that the ITS resources (number of LPIs, devices,
> events) later handed to a DomU are really limited, as a large number of
> them could mean much time spend in Xen to initialize, free or handle those.
> It is expected that the toolstack sets up a tailored ITS with just enough
> resources to accommodate the needs of the actual passthrough-ed device(s).
> - The command queue locking is currently suboptimal and should be made more
> fine-grained in the future, if possible.
> - Provide support for running with an IOMMU, to map the doorbell page
> to all devices.
>
>
> Some generic design principles:
>
> * The current GIC code statically allocates structures for each supported
> IRQ (both for the host and the guest), which due to the potentially
> millions of LPI interrupts is not feasible to copy for the ITS.
> So we refrain from introducing the ITS as a first class Xen interrupt
> controller, also we don't hold struct irq_desc's or struct pending_irq's
> for each possible LPI.
> Fortunately LPIs are only interesting to guests, so we get away with
> storing only the virtual IRQ number and the guest VCPU for each allocated
> host LPI, which can be stashed into one uint64_t. This data is stored in
> a two-level table, which is both memory efficient and quick to access.
> We hook into the existing IRQ handling and VGIC code to avoid accessing
> the normal structures, providing alternative methods for getting the
> needed information (priority, is enabled?) for LPIs.
> Whenever a guest maps a device, we allocate the maximum required number
> of struct pending_irq's, so that any triggering LPI can find its data
> structure. Upon the guest actually mapping the LPI, this pointer to the
> corresponding pending_irq gets entered into a radix tree, so that it can
> be quickly looked up.
>
> * On the guest side we (later will) have to deal with malicious guests
> trying to hog Xen with mapping requests for a lot of LPIs, for instance.
> As the ITS actually uses system memory for storing status information,
> we use this memory (which the guest has to provide) to naturally limit
> a guest. Whenever we need information from any of the ITS tables, we
> temporarily map them (which is cheap on arm64) and copy the required data.
>
> * An obvious approach to handling some guest ITS commands would be to
> propagate them to the host, for instance to map devices and LPIs and
> to enable or disable LPIs.
> However this (later with DomU support) will create an attack vector, as
> a malicious guest could try to fill the host command queue with
> propagated commands.
> So we try to avoid this situation: Dom0 sending a device mapping (MAPD)
> command is the only time we allow queuing commands to the host ITS command
> queue, as this seems to be the only reliable way of getting the
> required information at the moment. However at the same time we map all
> events to LPIs already, also enable them. This avoids sending commands
> later at runtime, as we can deal with mappings and LPI enabling/disabling
> internally.
>
> To accomodate the tech preview nature of this feature at the moment, there
> is a Kconfig option to enable it. Also it is supported on arm64 only, which
> will most likely not change in the future.
> This leads to some hideous constructs like an #ifdef'ed header file with
> empty function stubs to accomodate arm32 and non-ITS builds, which share
> some generic code paths with the ITS emulation.
> The number of supported LPIs can be limited on the command line, in case
> the number reported by the hardware is too high. As Xen cannot foresee how
> many interrupts the guests will need, we cater for as many as possible.
> The command line parameter is called max-lpi-bits and expresses the number
> of bits required to hold an interrupt ID. It defaults to 20, if that is
> lower than the number supported by the hardware.
>
> This code boots Dom0 on an ARM Fast Model with ITS support. I tried to
> address the issues seen by people running the previous versions on real
> hardware, though couldn't verify this here for myself.
> So any testing, bug reports (and possibly even fixes) are very welcome.
>
> The code can also be found on the its/v11 branch here:
> git://linux-arm.org/xen-ap.git
> http://www.linux-arm.org/git?p=xen-ap.git;a=shortlog;h=refs/heads/its/v11
>
> Cheers,
> Andre
>
> Changelog v10 ... v11:
> - [01/34]: use proper ACCESS_ONCE wrappers for all users
> - [02/34]: split of v9-12/32 for backporting
> - [03/34]: remainder of splitting v9-12/32
> - [04/34]: extend comment to justify 10 INITD bits
> - [05/34]: swapped place with former 04/32 to fix temporary deadlock
> - [06/34]: swapped place with former 03/32 to fix temporary deadlock
> - [08/34]: update commit message
> - [10/34]: remove unneeded p->lr initialisation
> - [11/34]: replace read_atomic with ACCESS_ONCE
> - [13/34]: split of former 11/32: remove no longer needed vCPU ID in host LPI
> - [14/34]: export inject_lpi, fix lock-less access to vCPU ID
> - [18/34]: fix commit message, add one more memory barrier and comment
> - [19/34]: fix its_cmd_mask_field(), dump ITS command on error
> - [20/34]: drop lock-taking versions of {read,write}_itte, drop optional vCPU
>             parameter to write_itte(), remove sanity checks (dony by callers)
> - [21/34]: fix "veventid" parameter name
> - [22/34]: explicitly take lock around read_itte, use vgic_vcpu_inject_lpi()
> - [25/34]: fix "veventid" parameter name
> - [26/34]: add unlikely() hints
> - [27/34]: remove unneeded read_atomic(), explicitly sanitize collection
> - [28/34]: extend IRQ migration comment
> - [30/34]: protects against not valid property table
> - [31/34]: protects against not valid property table, fix error propagation
>
> Changelog v9 ... v10:
> no changes to 06, 07, 12, 15, 20, 29, 30, 32
> - [01/32]: fix for rank lock deadlock as posted before
> - [02/32]: replace arbitrary 16 bits for DomU interrupt IDs with 10 bits
> - [03/32]: handle functions not dealing with LPIs as well
> - [04/32]: new patch to rename gic_remove_from_queues and remove lock
> - [05/32]: new patch to introduce helper for removing IRQs from the VGIC
> - [06/32]: adapt to previous changes
> - [08/32]: use memset to clear the whole structure
> - [09/32]: split off from former 05/28
> - [10/32]: moved up front, initialize VCPU ID
> - [11/32]: remove VCPU ID from host entry, rework LPI injection, moved
>             out part dealing with LPI priority caching
> - [13/32]: add a hint about boolean variables
> - [14/32]: fix bool_t type usage
> - [16/32]: replace magic value, always use intid_bits for TYPER generation,
>             add memory barrier
> - [17/32]: add comments about ITS table layout, remove le64_to_cpu(),
>             simplify CTLR read and remove lock, use atomic read and add comment
>             in CREADR read, add TODO and ASSERT about crafting ITS tables,
>             add empty lines in switch/case, move code block
> - [18/32]: consistent use of data types, comments moved out to earlier patch
> - [19/32]: fold in get_host_lpi(), rename veventid identifier
> - [21/32]: move variable assignment
> - [22/32]: add TODO locking comment, use new gic_remove_irq() function
> - [23/32]: remove no longer needed VCPU ID from host LPI functions, add
>             locking TODO, use goto out
> - [24/32]: explain reason for LR check, make LRs unsigned, move PRISTINE
>             check into one place
> - [25/32]: mention MAPI, remove VCPU ID from host LPI updates, use atomic
>             write for priority update, remove outdated comment, explain
>             error handling path, check for valid property table
> - [26/32]: remove update of VCPU ID in the host_lpi structure, add locking TODO
> - [27/32]: fix error path
> - [28/32]: add comment about physical LPI, use generic function to remove IRQ,
>             remove redundant clear_bit
> - [31/32]: make vgic_v3_its_init_virtual() static (and move it), move comment,
>             remove unneeded call to vgic_v3_its_free_domain()
>
> Changelog v8 ... v9:
> - [01/28]: initialize number of interrupt IDs for DomUs also
> - [02/28]: move priority reading back up front
> - [03/28]: enumerate all call sites in commit message, add ASSERTs,
>             add "unlikely" hints, avoid skipping ASSERTs, add comment to
>             irq_to_pending() definition
> - [04/28]: explain expectation of device state while destroying domain
> - [05/28]: document case of invalid LPI, change dummy priority to 0xff
> - [08/28]: check cross page boundary condition early in function
> - [10/28]: initialize status and lr member as well
> - [11/28]: check lpi_vcpu_id to cover all virtual CPUs
> - [12/28]: add spin lock ASSERT
> - [13/28]: introduce types for our ITS table entries, fix error messages
> - [14/28]: use new ITS table entry types
> - [15/28]: new patch to introduce pending_irq lookup function
> - [17/28]: verify size of collection table entry
> - [18/28]: use new pending_irq lookup function
> - [19/28]: use new pending_irq lookup function, collection table type and
>             vgic_init_pending_irq, add Dom0 ASSERT and unmap devices for DomUs
> - [20/28]: document PRISTINE_LPI flag, fix typo, avoid double insertion of
>             the same LPI into different LRs
> - [21/28]: use new pending_irq lookup function, avoid explict LPI number
>             parameter
> - [22/28]: add physical affinity TODO, use new table type and pending_irq
>             lookup function, fix error message
> - [24/28]: use pending_irq lookup function, drop explicit LPI number parameter
> - [25/28]: drop explicit LPI number parameter
> - [27/28]: use new ITS table entry type
>
> Changelog v7 ... v8:
> - drop list parameter and rename to gicv3_its_make_hwdwom_dt_nodes()
> - remove rebase artifacts
> - add irq_enter/irq_exit() calls
> - propagates number of host LPIs and number of event IDs to Dom0
> - add proper coverage of all addresses in ITS MMIO handler
> - avoid vcmd_lock for CBASER writes
> - fix missing irqsave/irqrestore on VGIC VCPU lock
> - move struct pending_irq use under the VGIC VCPU lock
> - protect gic_raise_guest_irq() against NULL pending_irq
> - improve device and collection table entry size documentation
> - count number of ITSes to increase mmio_count
> - rework MAPD, DISCARD, MAPTI and MOVI to take proper locks
> - properly rollback failing MAPD and MAPTI calls
> - rework functions to update property table
> - return error on vgic_access_guest_memory crossing page boundary
> - make sure CREADR access is atomic
>
> Changelog v5 ... v6:
> - reordered patches to allow splitting the series
> - introduced functions later to avoid warnings on intermediate builds
> - refactored common code changes into separate patches
> - dropped GENMASK_ULL and BIT_ULL (both patches and their usage later)
> - rework locking in MMIO register reads and writes
> - protect new code from being executed without an ITS being configured
> - fix vgic_access_guest_memory (now a separate patch)
> - some more comments and TODOs
>
> Changelog v4 ... v5:
> - adding many comments
> - spinlock asserts
> - rename r_host_lpis to max_host_lpi_ids
> - remove max_its_device_bits command line
> - add warning on high number of LPIs
> - avoid potential leak on host MAPD
> - properly handle nr_events rounding
> - remove unmap_all_devices(), replace with ASSERT
> - add barriers for (lockless) host LPI lookups
> - add proper locking in ITS and redist MMIO register handling
> - rollback failing device mapping
> - fix various printks
> - add vgic_access_guest_memory() and use it
> - (getting rid of page mapping functions and helpers)
> - drop table mapping / unmapping on redist/ITS enable/disable
> - minor reworks in functions as per review comments
> - fix ITS enablement check
> - move lpi_to_pending() and lpi_get_priority() to vgic_ops
> - move do_LPI() to gic_hw_ops
> - whitespace and hard tabs fixes
> - introduce ITS domain init function (and use it for the rbtree)
> - enable IRQs around do_LPI
> - implement TODOs for later optimizations
> - add "v" prefix to variables holding virtual properties
> - provide locked and normal versions of read/write_itte
> - only CLEAR LPI if not already guest visible (plus comment)
> - update LPI property on MAPTI
> - store vcpu_id in pending_irq for LPIs (helps INVALL)
> - improve INVALL implementation to only cover LPIs on this VCPU
> - improve virtual BASE register initialization
> - limit number of virtual LPIs to 24 bits (Linux bug at 32??)
> - only inject LPIs if redistributor is actually enabled
>
> Changelog v3 .. v4:
> - make HAS_ITS depend on EXPERT
> - introduce new patch 02 to initialize host ITS early
> - fix cmd_lock init position
> - introduce warning on high number of LPI allocations
> - various int -> unsigned fixes
> - adding and improving comments
> - rate limit ITS command queue full msg
> - drop unneeded checks
> - validate against allowed number of device IDs
> - avoid memory leaks when removing devices
> - improve algorithm for finding free host LPI
> - convert unmap_all_devices from goto to while loop
> - add message on remapping ITS device
> - name virtual device / event IDs properly
> - use atomic read when reading ITT entry
>
> Changelog v2 .. v3:
> - preallocate struct pending_irq's
> - map ITS and redistributor tables only on demand
> - store property, enable and pending bit in struct pending_irq
> - improve error checking and handling
> - add comments
>
> Changelog v1 .. v2:
> - clean up header file inclusion
> - rework host ITS table allocation: observe attributes, many fixes
> - remove patch 1 to export __flush_dcache_area, use existing function instead
> - use number of LPIs internally instead of number of bits
> - keep host_its_list as private as possible
> - keep struct its_devices private
> - rework gicv3_its_map_guest_devices
> - fix rbtree issues
> - more error handling and propagation
> - cope with GICv4 implementations (but no virtual LPI features!)
> - abstract host and guest ITSes by using doorbell addresses
> - join per-redistributor variables into one per-CPU structure
> - fix data types (unsigned int)
> - many minor bug fixes
>
> (Rough) changelog RFC-v2 .. v1:
> - split host ITS driver into gic-v3-lpi.c and gic-v3-its.c part
> - rename virtual ITS driver file to vgic-v3-its.c
> - use macros and named constants for all magic numbers
> - use atomic accessors for accessing the host LPI data
> - remove leftovers from connecting virtual and host ITSes
> - bail out if host ITS is disabled in the DT
> - rework map/unmap_guest_pages():
>      - split off p2m part as get/put_guest_pages (to be done on allocation)
>      - get rid of vmap, using map_domain_page() instead
> - delay allocation of virtual tables until actual LPI/ITS enablement
> - properly size both virtual and physical tables upon allocation
> - fix put_domain() locking issues in physdev_op and LPI handling code
> - add and extend comments in various areas
> - fix lotsa coding style and white space issues, including comment style
> - add locking to data structures not yet covered
> - fix various locking issues
> - use an rbtree to deal with ITS devices (instead of a list)
> - properly handle memory attributes for ITS tables
> - handle cacheable/non-cacheable ITS table mappings
> - sanitize guest provided ITS/LPI table attributes
> - fix breakage on non-GICv2 compatible host GICv3 controllers
> - add command line parameters on top of Kconfig options
> - properly wait for an ITS to become quiescient before enabling it
> - handle host ITS command queue errors
> - actually wait for host ITS command completion (READR==WRITER)
> - fix ARM32 compilation
> - various patch splits and reorderings
>
> Andre Przywara (33):
>    ARM: vGIC: avoid rank lock when reading priority
>    ARM: GICv3: enable ITS on the host
>    ARM: GICv3: enable LPIs on the host
>    ARM: GICv3: setup number of LPI bits for a GICv3 guest
>    ARM: vGIC: rework gic_remove_from_queues()
>    ARM: vGIC: move irq_to_pending() calls under the VGIC VCPU lock
>    ARM: vGIC: introduce gic_remove_irq()
>    ARM: GIC: Add checks for NULL pointer pending_irq's
>    ARM: GICv3: introduce separate pending_irq structs for LPIs
>    ARM: GIC: export and extend vgic_init_pending_irq()
>    ARM: vGIC: cache virtual LPI priority in struct pending_irq
>    ARM: vGIC: add LPI VCPU ID to struct pending_irq
>    ARM: GIC: ITS: remove no longer needed VCPU ID in host LPI entry
>    ARM: GICv3: forward pending LPIs to guests
>    ARM: vGICv3: handle virtual LPI pending and property tables
>    ARM: vGICv3: re-use vgic_reg64_check_access
>    ARM: vGIC: advertise LPI support
>    ARM: vITS: add command handling stub and MMIO emulation
>    ARM: vITS: introduce translation table walks
>    ARM: vITS: provide access to struct pending_irq
>    ARM: vITS: handle INT command
>    ARM: vITS: handle MAPC command
>    ARM: vITS: handle CLEAR command
>    ARM: vITS: handle MAPD command
>    ARM: GICv3: handle unmapped LPIs
>    ARM: vITS: handle MAPTI/MAPI command
>    ARM: vITS: handle MOVI command
>    ARM: vITS: handle DISCARD command
>    ARM: vITS: handle INV command
>    ARM: vITS: handle INVALL command
>    ARM: vITS: increase mmio_count for each ITS
>    ARM: vITS: create and initialize virtual ITSes for Dom0
>    ARM: vITS: create ITS subnodes for Dom0 DT
>
> Vijaya Kumar K (1):
>    ARM: introduce vgic_access_guest_memory()
>
>   xen/arch/arm/gic-v2.c            |    7 +
>   xen/arch/arm/gic-v3-its.c        |  180 +++++
>   xen/arch/arm/gic-v3-lpi.c        |   99 ++-
>   xen/arch/arm/gic-v3.c            |   29 +-
>   xen/arch/arm/gic.c               |  102 ++-
>   xen/arch/arm/vgic-v2.c           |   28 +-
>   xen/arch/arm/vgic-v3-its.c       | 1482 +++++++++++++++++++++++++++++++++++++-
>   xen/arch/arm/vgic-v3.c           |  327 ++++++++-
>   xen/arch/arm/vgic.c              |  146 +++-
>   xen/include/asm-arm/domain.h     |   16 +-
>   xen/include/asm-arm/event.h      |    3 +
>   xen/include/asm-arm/gic.h        |    5 +-
>   xen/include/asm-arm/gic_v3_its.h |   44 ++
>   xen/include/asm-arm/vgic-emul.h  |    9 +
>   xen/include/asm-arm/vgic.h       |   18 +-
>   15 files changed, 2413 insertions(+), 82 deletions(-)
>


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* Re: [PATCH v11 01/34] ARM: vGIC: avoid rank lock when reading priority
  2017-06-09 17:41 ` [PATCH v11 01/34] ARM: vGIC: avoid rank lock when reading priority Andre Przywara
@ 2017-06-12 14:49   ` Julien Grall
  2017-06-12 22:34     ` Stefano Stabellini
  0 siblings, 1 reply; 71+ messages in thread
From: Julien Grall @ 2017-06-12 14:49 UTC (permalink / raw)
  To: Andre Przywara, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

Hi Andre,

On 09/06/17 18:41, Andre Przywara wrote:
> When reading the priority value of a virtual interrupt, we were taking
> the respective rank lock so far.
> However for forwarded interrupts (Dom0 only so far) this may lead to a
> deadlock with the following call chain:
> - MMIO access to change the IRQ affinity, calling the ITARGETSR handler
> - this handler takes the appropriate rank lock and calls vgic_store_itargetsr()
> - vgic_store_itargetsr() will eventually call vgic_migrate_irq()
> - if this IRQ is already in-flight, it will remove it from the old
>   VCPU and inject it into the new one, by calling vgic_vcpu_inject_irq()
> - vgic_vcpu_inject_irq will call vgic_get_virq_priority()
> - vgic_get_virq_priority() tries to take the rank lock - again!
> It seems like this code path has never been exercised before.
>
> Fix this by avoiding taking the lock in vgic_get_virq_priority() (like we
> do in vgic_get_target_vcpu()).
> Actually we are just reading one byte, and priority changes while
> interrupts are handled are a benign race that can happen on real hardware
> too. So it is safe to just prevent the compiler from reading from the
> struct more than once.
>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  xen/arch/arm/vgic-v2.c | 13 ++++++++-----
>  xen/arch/arm/vgic-v3.c | 11 +++++++----
>  xen/arch/arm/vgic.c    |  8 +-------
>  3 files changed, 16 insertions(+), 16 deletions(-)
>
> diff --git a/xen/arch/arm/vgic-v2.c b/xen/arch/arm/vgic-v2.c
> index dc9f95b..5370020 100644
> --- a/xen/arch/arm/vgic-v2.c
> +++ b/xen/arch/arm/vgic-v2.c
> @@ -258,9 +258,9 @@ static int vgic_v2_distr_mmio_read(struct vcpu *v, mmio_info_t *info,
>          if ( rank == NULL ) goto read_as_zero;
>
>          vgic_lock_rank(v, rank, flags);
> -        ipriorityr = rank->ipriorityr[REG_RANK_INDEX(8,
> -                                                     gicd_reg - GICD_IPRIORITYR,
> -                                                     DABT_WORD)];
> +        ipriorityr = ACCESS_ONCE(rank->ipriorityr[REG_RANK_INDEX(8,
> +                                     gicd_reg - GICD_IPRIORITYR,
> +                                     DABT_WORD)]);

The indentation is a bit odd. Can you introduce a temporary variable here?

>          vgic_unlock_rank(v, rank, flags);
>          *r = vgic_reg32_extract(ipriorityr, info);
>
> @@ -499,7 +499,7 @@ static int vgic_v2_distr_mmio_write(struct vcpu *v, mmio_info_t *info,
>
>      case VRANGE32(GICD_IPRIORITYR, GICD_IPRIORITYRN):
>      {
> -        uint32_t *ipriorityr;
> +        uint32_t *ipriorityr, priority;
>
>          if ( dabt.size != DABT_BYTE && dabt.size != DABT_WORD ) goto bad_width;
>          rank = vgic_rank_offset(v, 8, gicd_reg - GICD_IPRIORITYR, DABT_WORD);
> @@ -508,7 +508,10 @@ static int vgic_v2_distr_mmio_write(struct vcpu *v, mmio_info_t *info,
>          ipriorityr = &rank->ipriorityr[REG_RANK_INDEX(8,
>                                                        gicd_reg - GICD_IPRIORITYR,
>                                                        DABT_WORD)];
> -        vgic_reg32_update(ipriorityr, r, info);
> +        priority = ACCESS_ONCE(*ipriorityr);
> +        vgic_reg32_update(&priority, r, info);
> +        ACCESS_ONCE(*ipriorityr) = priority;

This is a bit odd to read because of the dereferencing. I admit that I 
would prefer if you use read_atomic/write_atomic which are easier to 
understand (though the naming is confusing).

Let see what Stefano thinks here.

> +
>          vgic_unlock_rank(v, rank, flags);
>          return 1;
>      }
> diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
> index d10757a..8abc069 100644
> --- a/xen/arch/arm/vgic-v3.c
> +++ b/xen/arch/arm/vgic-v3.c
> @@ -521,8 +521,9 @@ static int __vgic_v3_distr_common_mmio_read(const char *name, struct vcpu *v,
>          if ( rank == NULL ) goto read_as_zero;
>
>          vgic_lock_rank(v, rank, flags);
> -        ipriorityr = rank->ipriorityr[REG_RANK_INDEX(8, reg - GICD_IPRIORITYR,
> -                                                     DABT_WORD)];
> +        ipriorityr = ACCESS_ONCE(rank->ipriorityr[REG_RANK_INDEX(8,
> +                                     reg - GICD_IPRIORITYR,
> +                                     DABT_WORD)]);

Ditto.


>          vgic_unlock_rank(v, rank, flags);
>
>          *r = vgic_reg32_extract(ipriorityr, info);
> @@ -630,7 +631,7 @@ static int __vgic_v3_distr_common_mmio_write(const char *name, struct vcpu *v,
>
>      case VRANGE32(GICD_IPRIORITYR, GICD_IPRIORITYRN):
>      {
> -        uint32_t *ipriorityr;
> +        uint32_t *ipriorityr, priority;
>
>          if ( dabt.size != DABT_BYTE && dabt.size != DABT_WORD ) goto bad_width;
>          rank = vgic_rank_offset(v, 8, reg - GICD_IPRIORITYR, DABT_WORD);
> @@ -638,7 +639,9 @@ static int __vgic_v3_distr_common_mmio_write(const char *name, struct vcpu *v,
>          vgic_lock_rank(v, rank, flags);
>          ipriorityr = &rank->ipriorityr[REG_RANK_INDEX(8, reg - GICD_IPRIORITYR,
>                                                        DABT_WORD)];
> -        vgic_reg32_update(ipriorityr, r, info);
> +        priority = ACCESS_ONCE(*ipriorityr);
> +        vgic_reg32_update(&priority, r, info);
> +        ACCESS_ONCE(*ipriorityr) = priority;

Ditto.

>          vgic_unlock_rank(v, rank, flags);
>          return 1;
>      }
> diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
> index 83569b0..18fe420 100644
> --- a/xen/arch/arm/vgic.c
> +++ b/xen/arch/arm/vgic.c
> @@ -227,14 +227,8 @@ struct vcpu *vgic_get_target_vcpu(struct vcpu *v, unsigned int virq)
>  static int vgic_get_virq_priority(struct vcpu *v, unsigned int virq)
>  {
>      struct vgic_irq_rank *rank = vgic_rank_irq(v, virq);
> -    unsigned long flags;
> -    int priority;
> -
> -    vgic_lock_rank(v, rank, flags);
> -    priority = rank->priority[virq & INTERRUPT_RANK_MASK];
> -    vgic_unlock_rank(v, rank, flags);
>
> -    return priority;
> +    return ACCESS_ONCE(rank->priority[virq & INTERRUPT_RANK_MASK]);
>  }
>
>  bool vgic_migrate_irq(struct vcpu *old, struct vcpu *new, unsigned int irq)
>

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* Re: [PATCH v11 02/34] ARM: GICv3: enable ITS on the host
  2017-06-09 17:41 ` [PATCH v11 02/34] ARM: GICv3: enable ITS on the host Andre Przywara
@ 2017-06-12 14:51   ` Julien Grall
  0 siblings, 0 replies; 71+ messages in thread
From: Julien Grall @ 2017-06-12 14:51 UTC (permalink / raw)
  To: Andre Przywara, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

Hi Andre,

On 09/06/17 18:41, Andre Przywara wrote:
> Even though the ITS emulation is not yet in place, the host ITS already
> gets initialized and Xen tries to map the host collections.
> However for commands to be processed we need to *enable* the ITS, which
> will be done in a later patch not yet merged.
> So those MAPC commands are not processed and run into a timeout, leading
> to a panic on machines which advertise an ITS in their DT.
> This patch just enables the ITS (but not the LPIs on each redistributor),
> to get those MAPC commands executed.
> This patch was part of: "ARM: GICv3: enable ITS and LPIs on the host"
> (patch v8 06/27 or v10 12/32, which was already acked by Stefano.

I don't think this paragraph belongs to the commit message. It should go 
after ---.

>
> This fixes booting Xen on ARM64 machines with an ITS and the
> (EXPERT) ITS Kconfig option enabled.
>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>

With the change above:

Acked-by: Julien Grall <julien.grall@arm.com>

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* Re: [PATCH v11 04/34] ARM: GICv3: setup number of LPI bits for a GICv3 guest
  2017-06-09 17:41 ` [PATCH v11 04/34] ARM: GICv3: setup number of LPI bits for a GICv3 guest Andre Przywara
@ 2017-06-12 15:03   ` Julien Grall
  0 siblings, 0 replies; 71+ messages in thread
From: Julien Grall @ 2017-06-12 15:03 UTC (permalink / raw)
  To: Andre Przywara, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

Hi Andre,

On 09/06/17 18:41, Andre Przywara wrote:
> The host supports a certain number of LPI identifiers, as stored in
> the GICD_TYPER register.
> Store this number from the hardware register in vgic_v3_hw to allow
> injecting the very same number into a guest (Dom0).
> DomUs get the legacy number of 10 bits here, since for now it only sees
> SPIs, so it does not need more. This should be revisited once we get
> proper DomU ITS support.
>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>

Acked-by: Julien Grall <julien.grall@arm.com>

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* Re: [PATCH v11 05/34] ARM: vGIC: rework gic_remove_from_queues()
  2017-06-09 17:41 ` [PATCH v11 05/34] ARM: vGIC: rework gic_remove_from_queues() Andre Przywara
@ 2017-06-12 15:15   ` Julien Grall
  0 siblings, 0 replies; 71+ messages in thread
From: Julien Grall @ 2017-06-12 15:15 UTC (permalink / raw)
  To: Andre Przywara, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

Hi Andre,

On 09/06/17 18:41, Andre Przywara wrote:
> The function name gic_remove_from_queues() was a bit of a misnomer,
> since it just removes an IRQ from the pending queue, not both queues.
> Rename the function to make this more clear, also give it a pointer to
> a struct pending_irq directly and rely on the VGIC VCPU lock to be
> already taken, so this can be used in more places.
> Replace the list removal in gic_clear_pending_irqs() with a call to
> this function.
>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  xen/arch/arm/gic.c        | 12 ++++--------
>  xen/arch/arm/vgic.c       |  5 ++++-
>  xen/include/asm-arm/gic.h |  2 +-
>  3 files changed, 9 insertions(+), 10 deletions(-)
>
> diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
> index da19130..6c0c9c3 100644
> --- a/xen/arch/arm/gic.c
> +++ b/xen/arch/arm/gic.c
> @@ -400,15 +400,11 @@ static inline void gic_add_to_lr_pending(struct vcpu *v, struct pending_irq *n)
>      list_add_tail(&n->lr_queue, &v->arch.vgic.lr_pending);
>  }
>
> -void gic_remove_from_queues(struct vcpu *v, unsigned int virtual_irq)
> +void gic_remove_from_lr_pending(struct vcpu *v, struct pending_irq *p)
>  {
> -    struct pending_irq *p = irq_to_pending(v, virtual_irq);
> -    unsigned long flags;
> +    ASSERT(spin_is_locked(&v->arch.vgic.lock));
>
> -    spin_lock_irqsave(&v->arch.vgic.lock, flags);
> -    if ( !list_empty(&p->lr_queue) )
> -        list_del_init(&p->lr_queue);
> -    spin_unlock_irqrestore(&v->arch.vgic.lock, flags);
> +    list_del_init(&p->lr_queue);
>  }
>
>  void gic_raise_inflight_irq(struct vcpu *v, unsigned int virtual_irq)
> @@ -609,7 +605,7 @@ void gic_clear_pending_irqs(struct vcpu *v)
>
>      v->arch.lr_mask = 0;
>      list_for_each_entry_safe ( p, t, &v->arch.vgic.lr_pending, lr_queue )
> -        list_del_init(&p->lr_queue);
> +        gic_remove_from_lr_pending(v, p);
>  }
>
>  int gic_events_need_delivery(void)
> diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
> index 18fe420..45926ab 100644
> --- a/xen/arch/arm/vgic.c
> +++ b/xen/arch/arm/vgic.c
> @@ -307,9 +307,12 @@ void vgic_disable_irqs(struct vcpu *v, uint32_t r, int n)
>      while ( (i = find_next_bit(&mask, 32, i)) < 32 ) {
>          irq = i + (32 * n);
>          v_target = vgic_get_target_vcpu(v, irq);
> +        spin_lock_irqsave(&v_target->arch.vgic.lock, flags);

Whilst I can understand why you move the lock here (because of #5) this 
should have required some explanation in the commit message. Indeed, 
leaving aside patch #5, there are no reason to take the lock for so long.

>          p = irq_to_pending(v_target, irq);
>          clear_bit(GIC_IRQ_GUEST_ENABLED, &p->status);
> -        gic_remove_from_queues(v_target, irq);
> +        gic_remove_from_lr_pending(v_target, p);
> +        spin_unlock_irqrestore(&v_target->arch.vgic.lock, flags);
> +
>          if ( p->desc != NULL )
>          {
>              spin_lock_irqsave(&p->desc->lock, flags);
> diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
> index 836a103..3130634 100644
> --- a/xen/include/asm-arm/gic.h
> +++ b/xen/include/asm-arm/gic.h
> @@ -243,7 +243,7 @@ extern void init_maintenance_interrupt(void);
>  extern void gic_raise_guest_irq(struct vcpu *v, unsigned int irq,
>          unsigned int priority);
>  extern void gic_raise_inflight_irq(struct vcpu *v, unsigned int virtual_irq);
> -extern void gic_remove_from_queues(struct vcpu *v, unsigned int virtual_irq);
> +extern void gic_remove_from_lr_pending(struct vcpu *v, struct pending_irq *p);
>
>  /* Accept an interrupt from the GIC and dispatch its handler */
>  extern void gic_interrupt(struct cpu_user_regs *regs, int is_fiq);
>

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* Re: [PATCH v11 06/34] ARM: vGIC: move irq_to_pending() calls under the VGIC VCPU lock
  2017-06-09 17:41 ` [PATCH v11 06/34] ARM: vGIC: move irq_to_pending() calls under the VGIC VCPU lock Andre Przywara
@ 2017-06-12 15:22   ` Julien Grall
  2017-06-12 22:43     ` Stefano Stabellini
  0 siblings, 1 reply; 71+ messages in thread
From: Julien Grall @ 2017-06-12 15:22 UTC (permalink / raw)
  To: Andre Przywara, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

Hi Andre,

On 09/06/17 18:41, Andre Przywara wrote:
> @@ -285,6 +291,17 @@ void arch_move_irqs(struct vcpu *v)
>      struct vcpu *v_target;
>      int i;
>
> +    /*
> +     * We don't migrate LPIs at the moment.
> +     * If we ever do, we must make sure that the struct pending_irq does
> +     * not go away, as there is no lock preventing this here.
> +     * To ensure this, we check if the loop below ever touches LPIs.
> +     * In the moment vgic_num_irqs() just covers SPIs, as it's mostly used
> +     * for allocating the pending_irq and irq_desc array, in which LPIs
> +     * don't participate.

IHMO, this paragraph should also be added on top of the definition 
vgic_num_irqs.

> +     */
> +    ASSERT(!is_lpi(vgic_num_irqs(d) - 1));
> +
>      for ( i = 32; i < vgic_num_irqs(d); i++ )
>      {
>          v_target = vgic_get_target_vcpu(v, i);
> @@ -299,6 +316,7 @@ void vgic_disable_irqs(struct vcpu *v, uint32_t r, int n)
>  {
>      const unsigned long mask = r;
>      struct pending_irq *p;
> +    struct irq_desc *desc;
>      unsigned int irq;
>      unsigned long flags;
>      int i = 0;
> @@ -307,17 +325,19 @@ void vgic_disable_irqs(struct vcpu *v, uint32_t r, int n)
>      while ( (i = find_next_bit(&mask, 32, i)) < 32 ) {
>          irq = i + (32 * n);
>          v_target = vgic_get_target_vcpu(v, irq);
> +

Spurious change.

>          spin_lock_irqsave(&v_target->arch.vgic.lock, flags);
>          p = irq_to_pending(v_target, irq);
>          clear_bit(GIC_IRQ_GUEST_ENABLED, &p->status);
>          gic_remove_from_lr_pending(v_target, p);
> +        desc = p->desc;
>          spin_unlock_irqrestore(&v_target->arch.vgic.lock, flags);

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* Re: [PATCH v11 07/34] ARM: vGIC: introduce gic_remove_irq()
  2017-06-09 17:41 ` [PATCH v11 07/34] ARM: vGIC: introduce gic_remove_irq() Andre Przywara
@ 2017-06-12 15:28   ` Julien Grall
  0 siblings, 0 replies; 71+ messages in thread
From: Julien Grall @ 2017-06-12 15:28 UTC (permalink / raw)
  To: Andre Przywara, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

Hi Andre,

On 09/06/17 18:41, Andre Przywara wrote:
> To avoid code duplication in a later patch, introduce a generic function
> to remove a virtual IRQ from the VGIC.
> Call that function instead of the open-coded version in vgic_migrate_irq().
>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  xen/arch/arm/gic.c        | 9 +++++++++
>  xen/arch/arm/vgic.c       | 4 +---
>  xen/include/asm-arm/gic.h | 1 +
>  3 files changed, 11 insertions(+), 3 deletions(-)
>
> diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
> index 6c0c9c3..e0c54d5 100644
> --- a/xen/arch/arm/gic.c
> +++ b/xen/arch/arm/gic.c
> @@ -407,6 +407,15 @@ void gic_remove_from_lr_pending(struct vcpu *v, struct pending_irq *p)
>      list_del_init(&p->lr_queue);
>  }
>
> +void gic_remove_irq(struct vcpu *v, struct pending_irq *p)

Again, the name is too generic. Remove IRQ from what?

> +{
> +    ASSERT(spin_is_locked(&v->arch.vgic.lock));
> +
> +    clear_bit(GIC_IRQ_GUEST_QUEUED, &p->status);
> +    list_del_init(&p->inflight);
> +    gic_remove_from_lr_pending(v, p);
> +}

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* Re: [PATCH v11 08/34] ARM: GIC: Add checks for NULL pointer pending_irq's
  2017-06-09 17:41 ` [PATCH v11 08/34] ARM: GIC: Add checks for NULL pointer pending_irq's Andre Przywara
@ 2017-06-12 15:30   ` Julien Grall
  2017-06-12 22:44   ` Stefano Stabellini
  1 sibling, 0 replies; 71+ messages in thread
From: Julien Grall @ 2017-06-12 15:30 UTC (permalink / raw)
  To: Andre Przywara, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

Hi Andre,

On 09/06/17 18:41, Andre Przywara wrote:
> For LPIs the struct pending_irq's are dynamically allocated and the
> pointers will be stored in a radix tree. Since an LPI can be "unmapped"
> at any time, teach the VGIC how to deal with irq_to_pending() returning
> a NULL pointer.
> We just do nothing in this case or clean up the LR if the virtual LPI
> number was still in an LR.
>
> Those are all call sites for irq_to_pending(), as per:
> "git grep irq_to_pending", and their evaluations:
> (PROTECTED means: added NULL check and bailing out)
>
>     xen/arch/arm/gic.c:
> gic_route_irq_to_guest(): only called for SPIs, added ASSERT()
> gic_remove_irq_from_guest(): only called for SPIs, added ASSERT()
> gic_remove_from_lr_pending(): PROTECTED, called within VCPU VGIC lock
> gic_raise_inflight_irq(): PROTECTED, called under VCPU VGIC lock
> gic_raise_guest_irq(): PROTECTED, called under VCPU VGIC lock
> gic_update_one_lr(): PROTECTED, called under VCPU VGIC lock
>
>     xen/arch/arm/vgic.c:
> vgic_migrate_irq(): not called for LPIs (virtual IRQs), added ASSERT()
> arch_move_irqs(): not iterating over LPIs, LPI ASSERT already in place
> vgic_disable_irqs(): not called for LPIs, added ASSERT()
> vgic_enable_irqs(): not called for LPIs, added ASSERT()
> vgic_vcpu_inject_irq(): PROTECTED, moved under VCPU VGIC lock
>
>     xen/include/asm-arm/event.h:
> local_events_need_delivery_nomask(): only called for a PPI, added ASSERT()
>
>     xen/include/asm-arm/vgic.h:
> (prototype)
>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>

Reviewed-by: Julien Grall <julien.grall@arm.com>

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* Re: [PATCH v11 10/34] ARM: GIC: export and extend vgic_init_pending_irq()
  2017-06-09 17:41 ` [PATCH v11 10/34] ARM: GIC: export and extend vgic_init_pending_irq() Andre Przywara
@ 2017-06-12 15:36   ` Julien Grall
  2017-06-14 15:54     ` Andre Przywara
  0 siblings, 1 reply; 71+ messages in thread
From: Julien Grall @ 2017-06-12 15:36 UTC (permalink / raw)
  To: Andre Przywara, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

Hi Andre,

On 09/06/17 18:41, Andre Przywara wrote:
> For LPIs we later want to dynamically allocate struct pending_irqs.
> So beside needing to initialize the struct from there we also need
> to clean it up and re-initialize it later on.
> Export vgic_init_pending_irq() and extend it to be reusable.
>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  xen/arch/arm/vgic.c        | 4 +++-
>  xen/include/asm-arm/vgic.h | 1 +
>  2 files changed, 4 insertions(+), 1 deletion(-)
>
> diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
> index 2e4820f..7e8dba6 100644
> --- a/xen/arch/arm/vgic.c
> +++ b/xen/arch/arm/vgic.c
> @@ -60,8 +60,10 @@ struct vgic_irq_rank *vgic_rank_irq(struct vcpu *v, unsigned int irq)
>      return vgic_get_rank(v, rank);
>  }
>
> -static void vgic_init_pending_irq(struct pending_irq *p, unsigned int virq)
> +void vgic_init_pending_irq(struct pending_irq *p, unsigned int virq)
>  {
> +    memset(p, 0, sizeof(*p));

So for initialization, we will clear the memory twice which looks rather 
pointless (see the current caller).

We probably to drop the memset or replace xzalloc by xalloc in the 
caller. I would be ok to see this change in a follow-up patch. Assuming 
you will sent a patch:

Reviewed-by: Julien Grall <julien.grall@arm.com>

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* Re: [PATCH v11 11/34] ARM: vGIC: cache virtual LPI priority in struct pending_irq
  2017-06-09 17:41 ` [PATCH v11 11/34] ARM: vGIC: cache virtual LPI priority in struct pending_irq Andre Przywara
@ 2017-06-12 15:39   ` Julien Grall
  0 siblings, 0 replies; 71+ messages in thread
From: Julien Grall @ 2017-06-12 15:39 UTC (permalink / raw)
  To: Andre Przywara, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

Hi Andre,

On 09/06/17 18:41, Andre Przywara wrote:
> We enhance struct pending_irq to cache the priority information
> for LPIs. Reading the information from there is faster than accessing
> the property table from guest memory. Also it use some padding area in
> the struct, so does not require more memory.
> This introduces the function to retrieve the LPI priority as a vgic_ops.
> Also this moves the vgic_get_virq_priority() call in
> vgic_vcpu_inject_irq() to happen after the NULL check of the pending_irq
> pointer, so we can rely on the pointer in the new function.
>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>

Acked-by: Julien Grall <julien.grall@arm.com>

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* Re: [PATCH v11 12/34] ARM: vGIC: add LPI VCPU ID to struct pending_irq
  2017-06-09 17:41 ` [PATCH v11 12/34] ARM: vGIC: add LPI VCPU ID to " Andre Przywara
@ 2017-06-12 15:46   ` Julien Grall
  0 siblings, 0 replies; 71+ messages in thread
From: Julien Grall @ 2017-06-12 15:46 UTC (permalink / raw)
  To: Andre Przywara, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

Hi Andre,

On 09/06/17 18:41, Andre Przywara wrote:
> The target CPU for an LPI is encoded in the interrupt translation table
> entry, so can't be easily derived from just an LPI number (short of
> walking *all* tables and find the matching LPI).
> To avoid this in case we need to know the VCPU (for the INVALL command,
> for instance), put the VCPU ID in the struct pending_irq, so that it is
> easily accessible.
> We use the remaining 8 bits of padding space for that to avoid enlarging
> the size of struct pending_irq. The number of VCPUs is limited to 127
> at the moment anyway, which we also confirm with a BUILD_BUG_ON.
>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>

Acked-by: Julien Grall <julien.grall@arm.com>

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* Re: [PATCH v11 13/34] ARM: GIC: ITS: remove no longer needed VCPU ID in host LPI entry
  2017-06-09 17:41 ` [PATCH v11 13/34] ARM: GIC: ITS: remove no longer needed VCPU ID in host LPI entry Andre Przywara
@ 2017-06-12 15:47   ` Julien Grall
  0 siblings, 0 replies; 71+ messages in thread
From: Julien Grall @ 2017-06-12 15:47 UTC (permalink / raw)
  To: Andre Przywara, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

Hi Andre,

On 09/06/17 18:41, Andre Przywara wrote:
> To get easy access to the VCPU a forwareded LPI interrupt should be

NIT: s/forwareded/forwarded/

> injected to, so far we stored the VCPU ID in the host LPI entry.
> However this creates a redundancy, since we keep the target VCPU in
> the struct pending_irq already, which we can easily look up given the
> domain and the virtual LPI number.
> Apart from removing the redundancy this avoids having to update this
> information later and keeping it in sync in a race-free fashion.
> Since this information has not been used that, this patch actually does
> not change anything, it just removes the declaration and initialization.
>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>

With the typo fixed:

Acked-by: Julien Grall <julien.grall@arm.com>

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* Re: [PATCH v11 14/34] ARM: GICv3: forward pending LPIs to guests
  2017-06-09 17:41 ` [PATCH v11 14/34] ARM: GICv3: forward pending LPIs to guests Andre Przywara
@ 2017-06-12 15:53   ` Julien Grall
  0 siblings, 0 replies; 71+ messages in thread
From: Julien Grall @ 2017-06-12 15:53 UTC (permalink / raw)
  To: Andre Przywara, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

Hi Andre,

On 09/06/17 18:41, Andre Przywara wrote:
> diff --git a/xen/arch/arm/gic-v3-lpi.c b/xen/arch/arm/gic-v3-lpi.c
> index dbaf45a..03d23b6 100644
> --- a/xen/arch/arm/gic-v3-lpi.c
> +++ b/xen/arch/arm/gic-v3-lpi.c
> @@ -136,6 +136,85 @@ uint64_t gicv3_get_redist_address(unsigned int cpu, bool use_pta)
>          return per_cpu(lpi_redist, cpu).redist_id << 16;
>  }
>
> +void vgic_vcpu_inject_lpi(struct domain *d, unsigned int virq)
> +{
> +    /*
> +     * TODO: this assumes that the struct pending_irq stays valid all of
> +     * time. We cannot properly protect this with the current locking

NIT: s/all of time/all of the time/ I think.

With that:

Acked-by: Julien Grall <julien.grall@arm.com>

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* Re: [PATCH v11 18/34] ARM: vGIC: advertise LPI support
  2017-06-09 17:41 ` [PATCH v11 18/34] ARM: vGIC: advertise LPI support Andre Przywara
@ 2017-06-12 16:02   ` Julien Grall
  0 siblings, 0 replies; 71+ messages in thread
From: Julien Grall @ 2017-06-12 16:02 UTC (permalink / raw)
  To: Andre Przywara, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

Hi Andre,

On 09/06/17 18:41, Andre Przywara wrote:
> To let a guest know about the availability of virtual LPIs, set the
> respective bits in the virtual GIC registers and let a guest control
> the LPI enable bit.
> Only report the LPI capability if there is at least one ITS emulated
> for that guest (which depends on the host having an ITS at the moment).
> For Dom0 we report the same number of interrupts identifiers as the
> host, whereas DomUs get a number fixed at 10 bits for the moments, which
> covers all SPIs. Also we fix a slight inaccuracy here, since the
> number of interrupt identifier specified in GICD_TYPER depends on the
> stream interface and is independent from the number of actually wired
> SPIs.
> This also removes a "TBD" comment, as we now populate the processor
> number in the GICR_TYPER register, which will be used by the ITS
> emulation later on.
>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>

Acked-by: Julien Grall <julien.grall@arm.com>

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* Re: [PATCH v11 19/34] ARM: vITS: add command handling stub and MMIO emulation
  2017-06-09 17:41 ` [PATCH v11 19/34] ARM: vITS: add command handling stub and MMIO emulation Andre Przywara
@ 2017-06-12 16:04   ` Julien Grall
  0 siblings, 0 replies; 71+ messages in thread
From: Julien Grall @ 2017-06-12 16:04 UTC (permalink / raw)
  To: Andre Przywara, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

Hi Andre,

On 09/06/17 18:41, Andre Przywara wrote:
> Emulate the memory mapped ITS registers and provide a stub to introduce
> the ITS command handling framework (but without actually emulating any
> commands at this time).
> This fixes a misnomer in our virtual ITS structure, where the spec is
> confusingly using ID_bits in GITS_TYPER to denote the number of event IDs
> (in contrast to GICD_TYPER, where it means number of LPIs).
>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>

Acked-by: Julien Grall <julien.grall@arm.com>

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* Re: [PATCH v11 20/34] ARM: vITS: introduce translation table walks
  2017-06-09 17:41 ` [PATCH v11 20/34] ARM: vITS: introduce translation table walks Andre Przywara
@ 2017-06-12 16:07   ` Julien Grall
  0 siblings, 0 replies; 71+ messages in thread
From: Julien Grall @ 2017-06-12 16:07 UTC (permalink / raw)
  To: Andre Przywara, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

Hi Andre,

On 09/06/17 18:41, Andre Przywara wrote:
> The ITS stores the target (v)CPU and the (virtual) LPI number in tables.
> Introduce functions to walk those tables and translate an device ID -
> event ID pair into a pair of virtual LPI and vCPU.
> We map those tables on demand - which is cheap on arm64 - and copy the
> respective entries before using them, to avoid the guest tampering with
> them meanwhile.
>
> To allow compiling without warnings, we declare two functions as
> non-static for the moment, which two later patches will fix.
>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>

Acked-by: Julien Grall <julien.grall@arm.com>

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* Re: [PATCH v11 24/34] ARM: vITS: handle CLEAR command
  2017-06-09 17:41 ` [PATCH v11 24/34] ARM: vITS: handle CLEAR command Andre Przywara
@ 2017-06-12 16:19   ` Julien Grall
  0 siblings, 0 replies; 71+ messages in thread
From: Julien Grall @ 2017-06-12 16:19 UTC (permalink / raw)
  To: Andre Przywara, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

Hi Andre,

On 09/06/17 18:41, Andre Przywara wrote:
> This introduces the ITS command handler for the CLEAR command, which
> clears the pending state of an LPI.
> This removes a not-yet injected, but already queued IRQ from a VCPU.
> As read_itte() is now eventually used, we add the static keyword.

Hmmm, you do that in patch #22 now. So please move this sentence in that 
patch.

>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> Acked-by: Julien Grall <julien.grall@arm.com>

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* Re: [PATCH v11 26/34] ARM: GICv3: handle unmapped LPIs
  2017-06-09 17:41 ` [PATCH v11 26/34] ARM: GICv3: handle unmapped LPIs Andre Przywara
@ 2017-06-12 16:30   ` Julien Grall
  0 siblings, 0 replies; 71+ messages in thread
From: Julien Grall @ 2017-06-12 16:30 UTC (permalink / raw)
  To: Andre Przywara, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

Hi Andre,

On 09/06/17 18:41, Andre Przywara wrote:
> @@ -478,8 +515,14 @@ static void gic_update_one_lr(struct vcpu *v, int i)
>      gic_hw_ops->read_lr(i, &lr_val);
>      irq = lr_val.virq;
>      p = irq_to_pending(v, irq);
> -    /* An LPI might have been unmapped, in which case we just clean up here. */
> -    if ( unlikely(!p) )
> +    /*
> +     * An LPI might have been unmapped, in which case we just clean up here.
> +     * If that LPI is marked as PRISTINE, the information in the LR is bogus,
> +     * as it belongs to a previous, already unmapped LPI. So we discard it
> +     * here as well.
> +     */
> +    if ( unlikely(!p ||
> +         test_and_clear_bit(GIC_IRQ_GUEST_PRISTINE_LPI, &p->status)) )

NIT: !p and test_and_clear_bit should be aligned. By that I mean:

unlikely(!p ||
          test_and_clear_bit(....)

With that:

Acked-by: Julien Grall <julien.grall@arm.com>

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* Re: [PATCH v11 27/34] ARM: vITS: handle MAPTI/MAPI command
  2017-06-09 17:41 ` [PATCH v11 27/34] ARM: vITS: handle MAPTI/MAPI command Andre Przywara
@ 2017-06-12 16:36   ` Julien Grall
  0 siblings, 0 replies; 71+ messages in thread
From: Julien Grall @ 2017-06-12 16:36 UTC (permalink / raw)
  To: Andre Przywara, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

Hi Andre,

On 09/06/17 18:41, Andre Przywara wrote:
> The MAPTI commands associates a DeviceID/EventID pair with a LPI/CPU
> pair and actually instantiates LPI interrupts. MAPI is just a variant
> of this comment, where the LPI ID is the same as the event ID.
> We connect the already allocated host LPI to this virtual LPI, so that
> any triggering LPI on the host can be quickly forwarded to a guest.
> Beside entering the domain and the virtual LPI number in the respective
> host LPI entry, we also initialize and add the already allocated
> struct pending_irq to our radix tree, so that we can now easily find it
> by its virtual LPI number.
> We also read the property table to update the enabled bit and the
> priority for our new LPI, as we might have missed this during an earlier
> INVALL call (which only checks mapped LPIs). But we make sure that the
> property table is actually valid, as all redistributors might still
> be disabled at this point.
> Since write_itte_locked() now sees its first usage, we change the

NIT: s/write_itte_locked/write_itte/

> declaration to static.
>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>

With the update in the commit message:

Acked-by: Julien Grall <julien.grall@arm.com>

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* Re: [PATCH v11 28/34] ARM: vITS: handle MOVI command
  2017-06-09 17:41 ` [PATCH v11 28/34] ARM: vITS: handle MOVI command Andre Przywara
@ 2017-06-12 16:37   ` Julien Grall
  0 siblings, 0 replies; 71+ messages in thread
From: Julien Grall @ 2017-06-12 16:37 UTC (permalink / raw)
  To: Andre Przywara, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

Hi Andre,

On 09/06/17 18:41, Andre Przywara wrote:
> The MOVI command moves the interrupt affinity from one redistributor
> (read: VCPU) to another.
> For now migration of "live" LPIs is not yet implemented, but we store
> the changed affinity in our virtual ITTE and the pending_irq.
>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>

Acked-by: Julien Grall <julien.grall@arm.com>

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* Re: [PATCH v11 31/34] ARM: vITS: handle INVALL command
  2017-06-09 17:41 ` [PATCH v11 31/34] ARM: vITS: handle INVALL command Andre Przywara
@ 2017-06-12 16:41   ` Julien Grall
  0 siblings, 0 replies; 71+ messages in thread
From: Julien Grall @ 2017-06-12 16:41 UTC (permalink / raw)
  To: Andre Przywara, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

Hi Andre,

On 09/06/17 18:41, Andre Przywara wrote:
> The INVALL command instructs an ITS to invalidate the configuration
> data for all LPIs associated with a given redistributor (read: VCPU).
> This is nasty to emulate exactly with our architecture, so we just
> iterate over all mapped LPIs and filter for those from that particular
> VCPU.
>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>

Acked-by: Julien Grall <julien.grall@arm.com>

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* Re: [PATCH v11 01/34] ARM: vGIC: avoid rank lock when reading priority
  2017-06-12 14:49   ` Julien Grall
@ 2017-06-12 22:34     ` Stefano Stabellini
  2017-06-13  9:01       ` Julien Grall
  0 siblings, 1 reply; 71+ messages in thread
From: Stefano Stabellini @ 2017-06-12 22:34 UTC (permalink / raw)
  To: Julien Grall
  Cc: Stefano Stabellini, Vijay Kilari, Manish Jaggi, Andre Przywara,
	Vijaya Kumar K, xen-devel, Shanker Donthineni

On Mon, 12 Jun 2017, Julien Grall wrote:
> Hi Andre,
> 
> On 09/06/17 18:41, Andre Przywara wrote:
> > When reading the priority value of a virtual interrupt, we were taking
> > the respective rank lock so far.
> > However for forwarded interrupts (Dom0 only so far) this may lead to a
> > deadlock with the following call chain:
> > - MMIO access to change the IRQ affinity, calling the ITARGETSR handler
> > - this handler takes the appropriate rank lock and calls
> > vgic_store_itargetsr()
> > - vgic_store_itargetsr() will eventually call vgic_migrate_irq()
> > - if this IRQ is already in-flight, it will remove it from the old
> >   VCPU and inject it into the new one, by calling vgic_vcpu_inject_irq()
> > - vgic_vcpu_inject_irq will call vgic_get_virq_priority()
> > - vgic_get_virq_priority() tries to take the rank lock - again!
> > It seems like this code path has never been exercised before.
> > 
> > Fix this by avoiding taking the lock in vgic_get_virq_priority() (like we
> > do in vgic_get_target_vcpu()).
> > Actually we are just reading one byte, and priority changes while
> > interrupts are handled are a benign race that can happen on real hardware
> > too. So it is safe to just prevent the compiler from reading from the
> > struct more than once.
> > 
> > Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> > ---
> >  xen/arch/arm/vgic-v2.c | 13 ++++++++-----
> >  xen/arch/arm/vgic-v3.c | 11 +++++++----
> >  xen/arch/arm/vgic.c    |  8 +-------
> >  3 files changed, 16 insertions(+), 16 deletions(-)
> > 
> > diff --git a/xen/arch/arm/vgic-v2.c b/xen/arch/arm/vgic-v2.c
> > index dc9f95b..5370020 100644
> > --- a/xen/arch/arm/vgic-v2.c
> > +++ b/xen/arch/arm/vgic-v2.c
> > @@ -258,9 +258,9 @@ static int vgic_v2_distr_mmio_read(struct vcpu *v,
> > mmio_info_t *info,
> >          if ( rank == NULL ) goto read_as_zero;
> > 
> >          vgic_lock_rank(v, rank, flags);
> > -        ipriorityr = rank->ipriorityr[REG_RANK_INDEX(8,
> > -                                                     gicd_reg -
> > GICD_IPRIORITYR,
> > -                                                     DABT_WORD)];
> > +        ipriorityr = ACCESS_ONCE(rank->ipriorityr[REG_RANK_INDEX(8,
> > +                                     gicd_reg - GICD_IPRIORITYR,
> > +                                     DABT_WORD)]);
> 
> The indentation is a bit odd. Can you introduce a temporary variable here?
> 
> >          vgic_unlock_rank(v, rank, flags);
> >          *r = vgic_reg32_extract(ipriorityr, info);
> > 
> > @@ -499,7 +499,7 @@ static int vgic_v2_distr_mmio_write(struct vcpu *v,
> > mmio_info_t *info,
> > 
> >      case VRANGE32(GICD_IPRIORITYR, GICD_IPRIORITYRN):
> >      {
> > -        uint32_t *ipriorityr;
> > +        uint32_t *ipriorityr, priority;
> > 
> >          if ( dabt.size != DABT_BYTE && dabt.size != DABT_WORD ) goto
> > bad_width;
> >          rank = vgic_rank_offset(v, 8, gicd_reg - GICD_IPRIORITYR,
> > DABT_WORD);
> > @@ -508,7 +508,10 @@ static int vgic_v2_distr_mmio_write(struct vcpu *v,
> > mmio_info_t *info,
> >          ipriorityr = &rank->ipriorityr[REG_RANK_INDEX(8,
> >                                                        gicd_reg -
> > GICD_IPRIORITYR,
> >                                                        DABT_WORD)];
> > -        vgic_reg32_update(ipriorityr, r, info);
> > +        priority = ACCESS_ONCE(*ipriorityr);
> > +        vgic_reg32_update(&priority, r, info);
> > +        ACCESS_ONCE(*ipriorityr) = priority;
> 
> This is a bit odd to read because of the dereferencing. I admit that I would
> prefer if you use read_atomic/write_atomic which are easier to understand
> (though the naming is confusing).
> 
> Let see what Stefano thinks here.

I also prefer *_atomic, especially given what Jan wrote about
ACCESS_ONCE:

  Plus ACCESS_ONCE() doesn't enforce a single instruction to be used in
  the resulting assembly).



> > +
> >          vgic_unlock_rank(v, rank, flags);
> >          return 1;
> >      }
> > diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
> > index d10757a..8abc069 100644
> > --- a/xen/arch/arm/vgic-v3.c
> > +++ b/xen/arch/arm/vgic-v3.c
> > @@ -521,8 +521,9 @@ static int __vgic_v3_distr_common_mmio_read(const char
> > *name, struct vcpu *v,
> >          if ( rank == NULL ) goto read_as_zero;
> > 
> >          vgic_lock_rank(v, rank, flags);
> > -        ipriorityr = rank->ipriorityr[REG_RANK_INDEX(8, reg -
> > GICD_IPRIORITYR,
> > -                                                     DABT_WORD)];
> > +        ipriorityr = ACCESS_ONCE(rank->ipriorityr[REG_RANK_INDEX(8,
> > +                                     reg - GICD_IPRIORITYR,
> > +                                     DABT_WORD)]);
> 
> Ditto.
> 
> 
> >          vgic_unlock_rank(v, rank, flags);
> > 
> >          *r = vgic_reg32_extract(ipriorityr, info);
> > @@ -630,7 +631,7 @@ static int __vgic_v3_distr_common_mmio_write(const char
> > *name, struct vcpu *v,
> > 
> >      case VRANGE32(GICD_IPRIORITYR, GICD_IPRIORITYRN):
> >      {
> > -        uint32_t *ipriorityr;
> > +        uint32_t *ipriorityr, priority;
> > 
> >          if ( dabt.size != DABT_BYTE && dabt.size != DABT_WORD ) goto
> > bad_width;
> >          rank = vgic_rank_offset(v, 8, reg - GICD_IPRIORITYR, DABT_WORD);
> > @@ -638,7 +639,9 @@ static int __vgic_v3_distr_common_mmio_write(const char
> > *name, struct vcpu *v,
> >          vgic_lock_rank(v, rank, flags);
> >          ipriorityr = &rank->ipriorityr[REG_RANK_INDEX(8, reg -
> > GICD_IPRIORITYR,
> >                                                        DABT_WORD)];
> > -        vgic_reg32_update(ipriorityr, r, info);
> > +        priority = ACCESS_ONCE(*ipriorityr);
> > +        vgic_reg32_update(&priority, r, info);
> > +        ACCESS_ONCE(*ipriorityr) = priority;
> 
> Ditto.
> 
> >          vgic_unlock_rank(v, rank, flags);
> >          return 1;
> >      }
> > diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
> > index 83569b0..18fe420 100644
> > --- a/xen/arch/arm/vgic.c
> > +++ b/xen/arch/arm/vgic.c
> > @@ -227,14 +227,8 @@ struct vcpu *vgic_get_target_vcpu(struct vcpu *v,
> > unsigned int virq)
> >  static int vgic_get_virq_priority(struct vcpu *v, unsigned int virq)
> >  {
> >      struct vgic_irq_rank *rank = vgic_rank_irq(v, virq);
> > -    unsigned long flags;
> > -    int priority;
> > -
> > -    vgic_lock_rank(v, rank, flags);
> > -    priority = rank->priority[virq & INTERRUPT_RANK_MASK];
> > -    vgic_unlock_rank(v, rank, flags);
> > 
> > -    return priority;
> > +    return ACCESS_ONCE(rank->priority[virq & INTERRUPT_RANK_MASK]);
> >  }
> > 
> >  bool vgic_migrate_irq(struct vcpu *old, struct vcpu *new, unsigned int irq)
> > 
> 
> Cheers,
> 
> -- 
> Julien Grall
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* Re: [PATCH v11 06/34] ARM: vGIC: move irq_to_pending() calls under the VGIC VCPU lock
  2017-06-12 15:22   ` Julien Grall
@ 2017-06-12 22:43     ` Stefano Stabellini
  0 siblings, 0 replies; 71+ messages in thread
From: Stefano Stabellini @ 2017-06-12 22:43 UTC (permalink / raw)
  To: Julien Grall
  Cc: Stefano Stabellini, Vijay Kilari, Manish Jaggi, Andre Przywara,
	Vijaya Kumar K, xen-devel, Shanker Donthineni

On Mon, 12 Jun 2017, Julien Grall wrote:
> Hi Andre,
> 
> On 09/06/17 18:41, Andre Przywara wrote:
> > @@ -285,6 +291,17 @@ void arch_move_irqs(struct vcpu *v)
> >      struct vcpu *v_target;
> >      int i;
> > 
> > +    /*
> > +     * We don't migrate LPIs at the moment.
> > +     * If we ever do, we must make sure that the struct pending_irq does
> > +     * not go away, as there is no lock preventing this here.
> > +     * To ensure this, we check if the loop below ever touches LPIs.
> > +     * In the moment vgic_num_irqs() just covers SPIs, as it's mostly used
> > +     * for allocating the pending_irq and irq_desc array, in which LPIs
> > +     * don't participate.
> 
> IHMO, this paragraph should also be added on top of the definition
> vgic_num_irqs.
> 
> > +     */
> > +    ASSERT(!is_lpi(vgic_num_irqs(d) - 1));
> > +
> >      for ( i = 32; i < vgic_num_irqs(d); i++ )
> >      {
> >          v_target = vgic_get_target_vcpu(v, i);
> > @@ -299,6 +316,7 @@ void vgic_disable_irqs(struct vcpu *v, uint32_t r, int
> > n)
> >  {
> >      const unsigned long mask = r;
> >      struct pending_irq *p;
> > +    struct irq_desc *desc;
> >      unsigned int irq;
> >      unsigned long flags;
> >      int i = 0;
> > @@ -307,17 +325,19 @@ void vgic_disable_irqs(struct vcpu *v, uint32_t r, int
> > n)
> >      while ( (i = find_next_bit(&mask, 32, i)) < 32 ) {
> >          irq = i + (32 * n);
> >          v_target = vgic_get_target_vcpu(v, irq);
> > +
> 
> Spurious change.

I couldn't spot any errors in this patch. I don't have any comments
besides what Julien already wrote.



> >          spin_lock_irqsave(&v_target->arch.vgic.lock, flags);
> >          p = irq_to_pending(v_target, irq);
> >          clear_bit(GIC_IRQ_GUEST_ENABLED, &p->status);
> >          gic_remove_from_lr_pending(v_target, p);
> > +        desc = p->desc;
> >          spin_unlock_irqrestore(&v_target->arch.vgic.lock, flags);
> 
> Cheers,
> 
> -- 
> Julien Grall
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* Re: [PATCH v11 08/34] ARM: GIC: Add checks for NULL pointer pending_irq's
  2017-06-09 17:41 ` [PATCH v11 08/34] ARM: GIC: Add checks for NULL pointer pending_irq's Andre Przywara
  2017-06-12 15:30   ` Julien Grall
@ 2017-06-12 22:44   ` Stefano Stabellini
  1 sibling, 0 replies; 71+ messages in thread
From: Stefano Stabellini @ 2017-06-12 22:44 UTC (permalink / raw)
  To: Andre Przywara
  Cc: Stefano Stabellini, Vijay Kilari, Manish Jaggi, Vijaya Kumar K,
	Julien Grall, xen-devel, Shanker Donthineni

On Fri, 9 Jun 2017, Andre Przywara wrote:
> For LPIs the struct pending_irq's are dynamically allocated and the
> pointers will be stored in a radix tree. Since an LPI can be "unmapped"
> at any time, teach the VGIC how to deal with irq_to_pending() returning
> a NULL pointer.
> We just do nothing in this case or clean up the LR if the virtual LPI
> number was still in an LR.
> 
> Those are all call sites for irq_to_pending(), as per:
> "git grep irq_to_pending", and their evaluations:
> (PROTECTED means: added NULL check and bailing out)
> 
>     xen/arch/arm/gic.c:
> gic_route_irq_to_guest(): only called for SPIs, added ASSERT()
> gic_remove_irq_from_guest(): only called for SPIs, added ASSERT()
> gic_remove_from_lr_pending(): PROTECTED, called within VCPU VGIC lock
> gic_raise_inflight_irq(): PROTECTED, called under VCPU VGIC lock
> gic_raise_guest_irq(): PROTECTED, called under VCPU VGIC lock
> gic_update_one_lr(): PROTECTED, called under VCPU VGIC lock
> 
>     xen/arch/arm/vgic.c:
> vgic_migrate_irq(): not called for LPIs (virtual IRQs), added ASSERT()
> arch_move_irqs(): not iterating over LPIs, LPI ASSERT already in place
> vgic_disable_irqs(): not called for LPIs, added ASSERT()
> vgic_enable_irqs(): not called for LPIs, added ASSERT()
> vgic_vcpu_inject_irq(): PROTECTED, moved under VCPU VGIC lock
> 
>     xen/include/asm-arm/event.h:
> local_events_need_delivery_nomask(): only called for a PPI, added ASSERT()
> 
>     xen/include/asm-arm/vgic.h:
> (prototype)
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>

Acked-by: Stefano Stabellini <sstabellini@kernel.org>


> ---
>  xen/arch/arm/gic.c          | 26 ++++++++++++++++++++++++--
>  xen/arch/arm/vgic.c         | 21 +++++++++++++++++++++
>  xen/include/asm-arm/event.h |  3 +++
>  3 files changed, 48 insertions(+), 2 deletions(-)
> 
> diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
> index e0c54d5..36e340b 100644
> --- a/xen/arch/arm/gic.c
> +++ b/xen/arch/arm/gic.c
> @@ -148,6 +148,7 @@ int gic_route_irq_to_guest(struct domain *d, unsigned int virq,
>      /* Caller has already checked that the IRQ is an SPI */
>      ASSERT(virq >= 32);
>      ASSERT(virq < vgic_num_irqs(d));
> +    ASSERT(!is_lpi(virq));
>  
>      vgic_lock_rank(v_target, rank, flags);
>  
> @@ -184,6 +185,7 @@ int gic_remove_irq_from_guest(struct domain *d, unsigned int virq,
>      ASSERT(spin_is_locked(&desc->lock));
>      ASSERT(test_bit(_IRQ_GUEST, &desc->status));
>      ASSERT(p->desc == desc);
> +    ASSERT(!is_lpi(virq));
>  
>      vgic_lock_rank(v_target, rank, flags);
>  
> @@ -420,6 +422,10 @@ void gic_raise_inflight_irq(struct vcpu *v, unsigned int virtual_irq)
>  {
>      struct pending_irq *n = irq_to_pending(v, virtual_irq);
>  
> +    /* If an LPI has been removed meanwhile, there is nothing left to raise. */
> +    if ( unlikely(!n) )
> +        return;
> +
>      ASSERT(spin_is_locked(&v->arch.vgic.lock));
>  
>      if ( list_empty(&n->lr_queue) )
> @@ -439,20 +445,25 @@ void gic_raise_guest_irq(struct vcpu *v, unsigned int virtual_irq,
>  {
>      int i;
>      unsigned int nr_lrs = gic_hw_ops->info->nr_lrs;
> +    struct pending_irq *p = irq_to_pending(v, virtual_irq);
>  
>      ASSERT(spin_is_locked(&v->arch.vgic.lock));
>  
> +    if ( unlikely(!p) )
> +        /* An unmapped LPI does not need to be raised. */
> +        return;
> +
>      if ( v == current && list_empty(&v->arch.vgic.lr_pending) )
>      {
>          i = find_first_zero_bit(&this_cpu(lr_mask), nr_lrs);
>          if (i < nr_lrs) {
>              set_bit(i, &this_cpu(lr_mask));
> -            gic_set_lr(i, irq_to_pending(v, virtual_irq), GICH_LR_PENDING);
> +            gic_set_lr(i, p, GICH_LR_PENDING);
>              return;
>          }
>      }
>  
> -    gic_add_to_lr_pending(v, irq_to_pending(v, virtual_irq));
> +    gic_add_to_lr_pending(v, p);
>  }
>  
>  static void gic_update_one_lr(struct vcpu *v, int i)
> @@ -467,6 +478,17 @@ static void gic_update_one_lr(struct vcpu *v, int i)
>      gic_hw_ops->read_lr(i, &lr_val);
>      irq = lr_val.virq;
>      p = irq_to_pending(v, irq);
> +    /* An LPI might have been unmapped, in which case we just clean up here. */
> +    if ( unlikely(!p) )
> +    {
> +        ASSERT(is_lpi(irq));
> +
> +        gic_hw_ops->clear_lr(i);
> +        clear_bit(i, &this_cpu(lr_mask));
> +
> +        return;
> +    }
> +
>      if ( lr_val.state & GICH_LR_ACTIVE )
>      {
>          set_bit(GIC_IRQ_GUEST_ACTIVE, &p->status);
> diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
> index f0d288d..1edf93d 100644
> --- a/xen/arch/arm/vgic.c
> +++ b/xen/arch/arm/vgic.c
> @@ -236,6 +236,9 @@ bool vgic_migrate_irq(struct vcpu *old, struct vcpu *new, unsigned int irq)
>      unsigned long flags;
>      struct pending_irq *p;
>  
> +    /* This will never be called for an LPI, as we don't migrate them. */
> +    ASSERT(!is_lpi(irq));
> +
>      spin_lock_irqsave(&old->arch.vgic.lock, flags);
>  
>      p = irq_to_pending(old, irq);
> @@ -320,6 +323,9 @@ void vgic_disable_irqs(struct vcpu *v, uint32_t r, int n)
>      int i = 0;
>      struct vcpu *v_target;
>  
> +    /* LPIs will never be disabled via this function. */
> +    ASSERT(!is_lpi(32 * n + 31));
> +
>      while ( (i = find_next_bit(&mask, 32, i)) < 32 ) {
>          irq = i + (32 * n);
>          v_target = vgic_get_target_vcpu(v, irq);
> @@ -367,6 +373,9 @@ void vgic_enable_irqs(struct vcpu *v, uint32_t r, int n)
>      struct vcpu *v_target;
>      struct domain *d = v->domain;
>  
> +    /* LPIs will never be enabled via this function. */
> +    ASSERT(!is_lpi(32 * n + 31));
> +
>      while ( (i = find_next_bit(&mask, 32, i)) < 32 ) {
>          irq = i + (32 * n);
>          v_target = vgic_get_target_vcpu(v, irq);
> @@ -447,6 +456,12 @@ bool vgic_to_sgi(struct vcpu *v, register_t sgir, enum gic_sgi_mode irqmode,
>      return true;
>  }
>  
> +/*
> + * Returns the pointer to the struct pending_irq belonging to the given
> + * interrupt.
> + * This can return NULL if called for an LPI which has been unmapped
> + * meanwhile.
> + */
>  struct pending_irq *irq_to_pending(struct vcpu *v, unsigned int irq)
>  {
>      struct pending_irq *n;
> @@ -490,6 +505,12 @@ void vgic_vcpu_inject_irq(struct vcpu *v, unsigned int virq)
>      spin_lock_irqsave(&v->arch.vgic.lock, flags);
>  
>      n = irq_to_pending(v, virq);
> +    /* If an LPI has been removed, there is nothing to inject here. */
> +    if ( unlikely(!n) )
> +    {
> +        spin_unlock_irqrestore(&v->arch.vgic.lock, flags);
> +        return;
> +    }
>  
>      /* vcpu offline */
>      if ( test_bit(_VPF_down, &v->pause_flags) )
> diff --git a/xen/include/asm-arm/event.h b/xen/include/asm-arm/event.h
> index 5330dfe..caefa50 100644
> --- a/xen/include/asm-arm/event.h
> +++ b/xen/include/asm-arm/event.h
> @@ -19,6 +19,9 @@ static inline int local_events_need_delivery_nomask(void)
>      struct pending_irq *p = irq_to_pending(current,
>                                             current->domain->arch.evtchn_irq);
>  
> +    /* Does not work for LPIs. */
> +    ASSERT(!is_lpi(current->domain->arch.evtchn_irq));
> +
>      /* XXX: if the first interrupt has already been delivered, we should
>       * check whether any other interrupts with priority higher than the
>       * one in GICV_IAR are in the lr_pending queue or in the LR
> -- 
> 2.9.0
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* Re: [PATCH v11 01/34] ARM: vGIC: avoid rank lock when reading priority
  2017-06-12 22:34     ` Stefano Stabellini
@ 2017-06-13  9:01       ` Julien Grall
  2017-06-13 22:19         ` Stefano Stabellini
  0 siblings, 1 reply; 71+ messages in thread
From: Julien Grall @ 2017-06-13  9:01 UTC (permalink / raw)
  To: Stefano Stabellini
  Cc: Vijay Kilari, Manish Jaggi, Andre Przywara, Vijaya Kumar K,
	xen-devel, nd, Shanker Donthineni



On 12/06/2017 23:34, Stefano Stabellini wrote:
> On Mon, 12 Jun 2017, Julien Grall wrote:
>> Hi Andre,
>>
>> On 09/06/17 18:41, Andre Przywara wrote:
>>> When reading the priority value of a virtual interrupt, we were taking
>>> the respective rank lock so far.
>>> However for forwarded interrupts (Dom0 only so far) this may lead to a
>>> deadlock with the following call chain:
>>> - MMIO access to change the IRQ affinity, calling the ITARGETSR handler
>>> - this handler takes the appropriate rank lock and calls
>>> vgic_store_itargetsr()
>>> - vgic_store_itargetsr() will eventually call vgic_migrate_irq()
>>> - if this IRQ is already in-flight, it will remove it from the old
>>>   VCPU and inject it into the new one, by calling vgic_vcpu_inject_irq()
>>> - vgic_vcpu_inject_irq will call vgic_get_virq_priority()
>>> - vgic_get_virq_priority() tries to take the rank lock - again!
>>> It seems like this code path has never been exercised before.
>>>
>>> Fix this by avoiding taking the lock in vgic_get_virq_priority() (like we
>>> do in vgic_get_target_vcpu()).
>>> Actually we are just reading one byte, and priority changes while
>>> interrupts are handled are a benign race that can happen on real hardware
>>> too. So it is safe to just prevent the compiler from reading from the
>>> struct more than once.
>>>
>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>> ---
>>>  xen/arch/arm/vgic-v2.c | 13 ++++++++-----
>>>  xen/arch/arm/vgic-v3.c | 11 +++++++----
>>>  xen/arch/arm/vgic.c    |  8 +-------
>>>  3 files changed, 16 insertions(+), 16 deletions(-)
>>>
>>> diff --git a/xen/arch/arm/vgic-v2.c b/xen/arch/arm/vgic-v2.c
>>> index dc9f95b..5370020 100644
>>> --- a/xen/arch/arm/vgic-v2.c
>>> +++ b/xen/arch/arm/vgic-v2.c
>>> @@ -258,9 +258,9 @@ static int vgic_v2_distr_mmio_read(struct vcpu *v,
>>> mmio_info_t *info,
>>>          if ( rank == NULL ) goto read_as_zero;
>>>
>>>          vgic_lock_rank(v, rank, flags);
>>> -        ipriorityr = rank->ipriorityr[REG_RANK_INDEX(8,
>>> -                                                     gicd_reg -
>>> GICD_IPRIORITYR,
>>> -                                                     DABT_WORD)];
>>> +        ipriorityr = ACCESS_ONCE(rank->ipriorityr[REG_RANK_INDEX(8,
>>> +                                     gicd_reg - GICD_IPRIORITYR,
>>> +                                     DABT_WORD)]);
>>
>> The indentation is a bit odd. Can you introduce a temporary variable here?
>>
>>>          vgic_unlock_rank(v, rank, flags);
>>>          *r = vgic_reg32_extract(ipriorityr, info);
>>>
>>> @@ -499,7 +499,7 @@ static int vgic_v2_distr_mmio_write(struct vcpu *v,
>>> mmio_info_t *info,
>>>
>>>      case VRANGE32(GICD_IPRIORITYR, GICD_IPRIORITYRN):
>>>      {
>>> -        uint32_t *ipriorityr;
>>> +        uint32_t *ipriorityr, priority;
>>>
>>>          if ( dabt.size != DABT_BYTE && dabt.size != DABT_WORD ) goto
>>> bad_width;
>>>          rank = vgic_rank_offset(v, 8, gicd_reg - GICD_IPRIORITYR,
>>> DABT_WORD);
>>> @@ -508,7 +508,10 @@ static int vgic_v2_distr_mmio_write(struct vcpu *v,
>>> mmio_info_t *info,
>>>          ipriorityr = &rank->ipriorityr[REG_RANK_INDEX(8,
>>>                                                        gicd_reg -
>>> GICD_IPRIORITYR,
>>>                                                        DABT_WORD)];
>>> -        vgic_reg32_update(ipriorityr, r, info);
>>> +        priority = ACCESS_ONCE(*ipriorityr);
>>> +        vgic_reg32_update(&priority, r, info);
>>> +        ACCESS_ONCE(*ipriorityr) = priority;
>>
>> This is a bit odd to read because of the dereferencing. I admit that I would
>> prefer if you use read_atomic/write_atomic which are easier to understand
>> (though the naming is confusing).
>>
>> Let see what Stefano thinks here.
>
> I also prefer *_atomic, especially given what Jan wrote about
> ACCESS_ONCE:
>
>   Plus ACCESS_ONCE() doesn't enforce a single instruction to be used in
>   the resulting assembly).

I don't buy this argument. There are quite a few places we rely on 
assignment to be atomic (see PV protocols for instance). Furthermore 
implementation of atomic_read/atomic_write in Linux (both ARM and x86) 
is based on WRITE_ONCE/READ_ONCE, on Xen it is a simple assignment.

In any case, all those macros does not prevent re-ordering at the 
processor level nor read/write atomicity if the variable is misaligned.

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* Re: [PATCH v11 25/34] ARM: vITS: handle MAPD command
  2017-06-09 17:41 ` [PATCH v11 25/34] ARM: vITS: handle MAPD command Andre Przywara
@ 2017-06-13 22:02   ` Stefano Stabellini
  0 siblings, 0 replies; 71+ messages in thread
From: Stefano Stabellini @ 2017-06-13 22:02 UTC (permalink / raw)
  To: Andre Przywara
  Cc: Stefano Stabellini, Vijay Kilari, Manish Jaggi, Vijaya Kumar K,
	Julien Grall, xen-devel, Shanker Donthineni

On Fri, 9 Jun 2017, Andre Przywara wrote:
> @@ -375,6 +390,131 @@ out_unlock:
>      return ret;
>  }
>  
> +/* Must be called with the ITS lock held. */
> +static int its_discard_event(struct virt_its *its,
> +                             uint32_t vdevid, uint32_t vevid)
> +{
> +    struct pending_irq *p;
> +    unsigned long flags;
> +    struct vcpu *vcpu;
> +    uint32_t vlpi;
> +
> +    ASSERT(spin_is_locked(&its->its_lock));
> +
> +    if ( !read_itte(its, vdevid, vevid, &vcpu, &vlpi) )
> +        return -ENOENT;
> +
> +    if ( vlpi == INVALID_LPI )
> +        return -ENOENT;
> +
> +    /*
> +     * TODO: This relies on the VCPU being correct in the ITS tables.
> +     * This can be fixed by either using a per-IRQ lock or by using
> +     * the VCPU ID from the pending_irq instead.
> +     */
> +    spin_lock_irqsave(&vcpu->arch.vgic.lock, flags);
> +
> +    /* Remove the pending_irq from the tree. */
> +    write_lock(&its->d->arch.vgic.pend_lpi_tree_lock);
> +    p = radix_tree_delete(&its->d->arch.vgic.pend_lpi_tree, vlpi);
> +    write_unlock(&its->d->arch.vgic.pend_lpi_tree_lock);
> +
> +    if ( !p )
> +    {
> +        spin_unlock_irqrestore(&vcpu->arch.vgic.lock, flags);
> +
> +        return -ENOENT;
> +    }
> +
> +    /* Cleanup the pending_irq and disconnect it from the LPI. */
> +    list_del_init(&p->inflight);
> +    list_del_init(&p->lr_queue);
> +    vgic_init_pending_irq(p, INVALID_LPI);

Why not call gic_remove_irq?



_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* Re: [PATCH v11 01/34] ARM: vGIC: avoid rank lock when reading priority
  2017-06-13  9:01       ` Julien Grall
@ 2017-06-13 22:19         ` Stefano Stabellini
  2017-06-14  8:55           ` Julien Grall
  0 siblings, 1 reply; 71+ messages in thread
From: Stefano Stabellini @ 2017-06-13 22:19 UTC (permalink / raw)
  To: Julien Grall
  Cc: Stefano Stabellini, Vijay Kilari, Manish Jaggi, Andre Przywara,
	Vijaya Kumar K, xen-devel, nd, Shanker Donthineni

On Tue, 13 Jun 2017, Julien Grall wrote:
> On 12/06/2017 23:34, Stefano Stabellini wrote:
> > On Mon, 12 Jun 2017, Julien Grall wrote:
> > > Hi Andre,
> > > 
> > > On 09/06/17 18:41, Andre Przywara wrote:
> > > > When reading the priority value of a virtual interrupt, we were taking
> > > > the respective rank lock so far.
> > > > However for forwarded interrupts (Dom0 only so far) this may lead to a
> > > > deadlock with the following call chain:
> > > > - MMIO access to change the IRQ affinity, calling the ITARGETSR handler
> > > > - this handler takes the appropriate rank lock and calls
> > > > vgic_store_itargetsr()
> > > > - vgic_store_itargetsr() will eventually call vgic_migrate_irq()
> > > > - if this IRQ is already in-flight, it will remove it from the old
> > > >   VCPU and inject it into the new one, by calling vgic_vcpu_inject_irq()
> > > > - vgic_vcpu_inject_irq will call vgic_get_virq_priority()
> > > > - vgic_get_virq_priority() tries to take the rank lock - again!
> > > > It seems like this code path has never been exercised before.
> > > > 
> > > > Fix this by avoiding taking the lock in vgic_get_virq_priority() (like
> > > > we
> > > > do in vgic_get_target_vcpu()).
> > > > Actually we are just reading one byte, and priority changes while
> > > > interrupts are handled are a benign race that can happen on real
> > > > hardware
> > > > too. So it is safe to just prevent the compiler from reading from the
> > > > struct more than once.
> > > > 
> > > > Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> > > > ---
> > > >  xen/arch/arm/vgic-v2.c | 13 ++++++++-----
> > > >  xen/arch/arm/vgic-v3.c | 11 +++++++----
> > > >  xen/arch/arm/vgic.c    |  8 +-------
> > > >  3 files changed, 16 insertions(+), 16 deletions(-)
> > > > 
> > > > diff --git a/xen/arch/arm/vgic-v2.c b/xen/arch/arm/vgic-v2.c
> > > > index dc9f95b..5370020 100644
> > > > --- a/xen/arch/arm/vgic-v2.c
> > > > +++ b/xen/arch/arm/vgic-v2.c
> > > > @@ -258,9 +258,9 @@ static int vgic_v2_distr_mmio_read(struct vcpu *v,
> > > > mmio_info_t *info,
> > > >          if ( rank == NULL ) goto read_as_zero;
> > > > 
> > > >          vgic_lock_rank(v, rank, flags);
> > > > -        ipriorityr = rank->ipriorityr[REG_RANK_INDEX(8,
> > > > -                                                     gicd_reg -
> > > > GICD_IPRIORITYR,
> > > > -                                                     DABT_WORD)];
> > > > +        ipriorityr = ACCESS_ONCE(rank->ipriorityr[REG_RANK_INDEX(8,
> > > > +                                     gicd_reg - GICD_IPRIORITYR,
> > > > +                                     DABT_WORD)]);
> > > 
> > > The indentation is a bit odd. Can you introduce a temporary variable here?
> > > 
> > > >          vgic_unlock_rank(v, rank, flags);
> > > >          *r = vgic_reg32_extract(ipriorityr, info);
> > > > 
> > > > @@ -499,7 +499,7 @@ static int vgic_v2_distr_mmio_write(struct vcpu *v,
> > > > mmio_info_t *info,
> > > > 
> > > >      case VRANGE32(GICD_IPRIORITYR, GICD_IPRIORITYRN):
> > > >      {
> > > > -        uint32_t *ipriorityr;
> > > > +        uint32_t *ipriorityr, priority;
> > > > 
> > > >          if ( dabt.size != DABT_BYTE && dabt.size != DABT_WORD ) goto
> > > > bad_width;
> > > >          rank = vgic_rank_offset(v, 8, gicd_reg - GICD_IPRIORITYR,
> > > > DABT_WORD);
> > > > @@ -508,7 +508,10 @@ static int vgic_v2_distr_mmio_write(struct vcpu *v,
> > > > mmio_info_t *info,
> > > >          ipriorityr = &rank->ipriorityr[REG_RANK_INDEX(8,
> > > >                                                        gicd_reg -
> > > > GICD_IPRIORITYR,
> > > >                                                        DABT_WORD)];
> > > > -        vgic_reg32_update(ipriorityr, r, info);
> > > > +        priority = ACCESS_ONCE(*ipriorityr);
> > > > +        vgic_reg32_update(&priority, r, info);
> > > > +        ACCESS_ONCE(*ipriorityr) = priority;
> > > 
> > > This is a bit odd to read because of the dereferencing. I admit that I
> > > would
> > > prefer if you use read_atomic/write_atomic which are easier to understand
> > > (though the naming is confusing).
> > > 
> > > Let see what Stefano thinks here.
> > 
> > I also prefer *_atomic, especially given what Jan wrote about
> > ACCESS_ONCE:
> > 
> >   Plus ACCESS_ONCE() doesn't enforce a single instruction to be used in
> >   the resulting assembly).
> 
> I don't buy this argument. There are quite a few places we rely on assignment
> to be atomic (see PV protocols for instance).

I don't understand your explanation. There are no PV protocols under
xen/, they are implemented in other repositories. I grepped for ACCESS
under xen/include/public, in case you referred to the PV protocol
headers, but couldn't find anything interesting.


> Furthermore implementation of
> atomic_read/atomic_write in Linux (both ARM and x86) is based on
> WRITE_ONCE/READ_ONCE, on Xen it is a simple assignment.

I don't follow why you are referring to Linux constructs in this
discussion about Xen atomic functions.


> In any case, all those macros does not prevent re-ordering at the processor
> level nor read/write atomicity if the variable is misaligned.

My understanding is that the unwritten assumption in Xen is that
variables are always aligned. You are right about processor level
reordering, in fact when needed we have to have barriers.

I have read Andre's well written README.atomic, and he ends the
document stating the following:


> This makes read and write accesses to ints and longs (and their respective
> unsigned counter parts) naturally atomic.
> However it would be beneficial to use atomic primitives anyway to annotate
> the code as being concurrent and to prevent silent breakage when changing
> the code

with which I completely agree

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* Re: [PATCH v11 01/34] ARM: vGIC: avoid rank lock when reading priority
  2017-06-13 22:19         ` Stefano Stabellini
@ 2017-06-14  8:55           ` Julien Grall
  2017-06-14 11:22             ` Andre Przywara
  2017-06-14 17:32             ` Stefano Stabellini
  0 siblings, 2 replies; 71+ messages in thread
From: Julien Grall @ 2017-06-14  8:55 UTC (permalink / raw)
  To: Stefano Stabellini
  Cc: Vijay Kilari, Manish Jaggi, Andre Przywara, Vijaya Kumar K,
	xen-devel, nd, Shanker Donthineni



On 06/13/2017 11:19 PM, Stefano Stabellini wrote:
> On Tue, 13 Jun 2017, Julien Grall wrote:
>> On 12/06/2017 23:34, Stefano Stabellini wrote:
>>> On Mon, 12 Jun 2017, Julien Grall wrote:
>>>> Hi Andre,
>>>>
>>>> On 09/06/17 18:41, Andre Przywara wrote:
>>>>> When reading the priority value of a virtual interrupt, we were taking
>>>>> the respective rank lock so far.
>>>>> However for forwarded interrupts (Dom0 only so far) this may lead to a
>>>>> deadlock with the following call chain:
>>>>> - MMIO access to change the IRQ affinity, calling the ITARGETSR handler
>>>>> - this handler takes the appropriate rank lock and calls
>>>>> vgic_store_itargetsr()
>>>>> - vgic_store_itargetsr() will eventually call vgic_migrate_irq()
>>>>> - if this IRQ is already in-flight, it will remove it from the old
>>>>>    VCPU and inject it into the new one, by calling vgic_vcpu_inject_irq()
>>>>> - vgic_vcpu_inject_irq will call vgic_get_virq_priority()
>>>>> - vgic_get_virq_priority() tries to take the rank lock - again!
>>>>> It seems like this code path has never been exercised before.
>>>>>
>>>>> Fix this by avoiding taking the lock in vgic_get_virq_priority() (like
>>>>> we
>>>>> do in vgic_get_target_vcpu()).
>>>>> Actually we are just reading one byte, and priority changes while
>>>>> interrupts are handled are a benign race that can happen on real
>>>>> hardware
>>>>> too. So it is safe to just prevent the compiler from reading from the
>>>>> struct more than once.
>>>>>
>>>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>>>> ---
>>>>>   xen/arch/arm/vgic-v2.c | 13 ++++++++-----
>>>>>   xen/arch/arm/vgic-v3.c | 11 +++++++----
>>>>>   xen/arch/arm/vgic.c    |  8 +-------
>>>>>   3 files changed, 16 insertions(+), 16 deletions(-)
>>>>>
>>>>> diff --git a/xen/arch/arm/vgic-v2.c b/xen/arch/arm/vgic-v2.c
>>>>> index dc9f95b..5370020 100644
>>>>> --- a/xen/arch/arm/vgic-v2.c
>>>>> +++ b/xen/arch/arm/vgic-v2.c
>>>>> @@ -258,9 +258,9 @@ static int vgic_v2_distr_mmio_read(struct vcpu *v,
>>>>> mmio_info_t *info,
>>>>>           if ( rank == NULL ) goto read_as_zero;
>>>>>
>>>>>           vgic_lock_rank(v, rank, flags);
>>>>> -        ipriorityr = rank->ipriorityr[REG_RANK_INDEX(8,
>>>>> -                                                     gicd_reg -
>>>>> GICD_IPRIORITYR,
>>>>> -                                                     DABT_WORD)];
>>>>> +        ipriorityr = ACCESS_ONCE(rank->ipriorityr[REG_RANK_INDEX(8,
>>>>> +                                     gicd_reg - GICD_IPRIORITYR,
>>>>> +                                     DABT_WORD)]);
>>>>
>>>> The indentation is a bit odd. Can you introduce a temporary variable here?
>>>>
>>>>>           vgic_unlock_rank(v, rank, flags);
>>>>>           *r = vgic_reg32_extract(ipriorityr, info);
>>>>>
>>>>> @@ -499,7 +499,7 @@ static int vgic_v2_distr_mmio_write(struct vcpu *v,
>>>>> mmio_info_t *info,
>>>>>
>>>>>       case VRANGE32(GICD_IPRIORITYR, GICD_IPRIORITYRN):
>>>>>       {
>>>>> -        uint32_t *ipriorityr;
>>>>> +        uint32_t *ipriorityr, priority;
>>>>>
>>>>>           if ( dabt.size != DABT_BYTE && dabt.size != DABT_WORD ) goto
>>>>> bad_width;
>>>>>           rank = vgic_rank_offset(v, 8, gicd_reg - GICD_IPRIORITYR,
>>>>> DABT_WORD);
>>>>> @@ -508,7 +508,10 @@ static int vgic_v2_distr_mmio_write(struct vcpu *v,
>>>>> mmio_info_t *info,
>>>>>           ipriorityr = &rank->ipriorityr[REG_RANK_INDEX(8,
>>>>>                                                         gicd_reg -
>>>>> GICD_IPRIORITYR,
>>>>>                                                         DABT_WORD)];
>>>>> -        vgic_reg32_update(ipriorityr, r, info);
>>>>> +        priority = ACCESS_ONCE(*ipriorityr);
>>>>> +        vgic_reg32_update(&priority, r, info);
>>>>> +        ACCESS_ONCE(*ipriorityr) = priority;
>>>>
>>>> This is a bit odd to read because of the dereferencing. I admit that I
>>>> would
>>>> prefer if you use read_atomic/write_atomic which are easier to understand
>>>> (though the naming is confusing).
>>>>
>>>> Let see what Stefano thinks here.
>>>
>>> I also prefer *_atomic, especially given what Jan wrote about
>>> ACCESS_ONCE:
>>>
>>>    Plus ACCESS_ONCE() doesn't enforce a single instruction to be used in
>>>    the resulting assembly).
>>
>> I don't buy this argument. There are quite a few places we rely on assignment
>> to be atomic (see PV protocols for instance).
> 
> I don't understand your explanation. There are no PV protocols under
> xen/, they are implemented in other repositories. I grepped for ACCESS
> under xen/include/public, in case you referred to the PV protocol
> headers, but couldn't find anything interesting.

Have a look at the pl011 emulation from Bhupinder. It will use plain '=' 
for updating the PV drivers. So can you explain why it is fine there and 
not here?

> 
> 
>> Furthermore implementation of
>> atomic_read/atomic_write in Linux (both ARM and x86) is based on
>> WRITE_ONCE/READ_ONCE, on Xen it is a simple assignment.
> 
> I don't follow why you are referring to Linux constructs in this
> discussion about Xen atomic functions.

My point here is Xen and Linux are very similar. Actually a lot of the 
atomic code is been taken from Linux (have a look to our 
atomic_read/atomic_write).

As the atomic code was added the code by you (likely from Linux), I 
don't understand why you don't complain about the atomic implementation 
but ACCESS_ONCE.

> 
> 
>> In any case, all those macros does not prevent re-ordering at the processor
>> level nor read/write atomicity if the variable is misaligned.
> 
> My understanding is that the unwritten assumption in Xen is that
> variables are always aligned. You are right about processor level
> reordering, in fact when needed we have to have barriers
> 
> I have read Andre's well written README.atomic, and he ends the
> document stating the following:
> 
> 
>> This makes read and write accesses to ints and longs (and their respective
>> unsigned counter parts) naturally atomic.
>> However it would be beneficial to use atomic primitives anyway to annotate
>> the code as being concurrent and to prevent silent breakage when changing
>> the code
> 
> with which I completely agree

Which means you are happy to use either ACCESS_ONCE or 
read_atomic/write_atomic as they in-fine exactly the same on the 
compiler we support.

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* Re: [PATCH v11 01/34] ARM: vGIC: avoid rank lock when reading priority
  2017-06-14  8:55           ` Julien Grall
@ 2017-06-14 11:22             ` Andre Przywara
  2017-06-14 11:27               ` Julien Grall
  2017-06-14 17:32             ` Stefano Stabellini
  1 sibling, 1 reply; 71+ messages in thread
From: Andre Przywara @ 2017-06-14 11:22 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

Hi,

On 14/06/17 09:55, Julien Grall wrote:
> 
> 
> On 06/13/2017 11:19 PM, Stefano Stabellini wrote:
>> On Tue, 13 Jun 2017, Julien Grall wrote:
>>> On 12/06/2017 23:34, Stefano Stabellini wrote:
>>>> On Mon, 12 Jun 2017, Julien Grall wrote:
>>>>> Hi Andre,
>>>>>
>>>>> On 09/06/17 18:41, Andre Przywara wrote:
>>>>>> When reading the priority value of a virtual interrupt, we were
>>>>>> taking
>>>>>> the respective rank lock so far.
>>>>>> However for forwarded interrupts (Dom0 only so far) this may lead
>>>>>> to a
>>>>>> deadlock with the following call chain:
>>>>>> - MMIO access to change the IRQ affinity, calling the ITARGETSR
>>>>>> handler
>>>>>> - this handler takes the appropriate rank lock and calls
>>>>>> vgic_store_itargetsr()
>>>>>> - vgic_store_itargetsr() will eventually call vgic_migrate_irq()
>>>>>> - if this IRQ is already in-flight, it will remove it from the old
>>>>>>    VCPU and inject it into the new one, by calling
>>>>>> vgic_vcpu_inject_irq()
>>>>>> - vgic_vcpu_inject_irq will call vgic_get_virq_priority()
>>>>>> - vgic_get_virq_priority() tries to take the rank lock - again!
>>>>>> It seems like this code path has never been exercised before.
>>>>>>
>>>>>> Fix this by avoiding taking the lock in vgic_get_virq_priority()
>>>>>> (like
>>>>>> we
>>>>>> do in vgic_get_target_vcpu()).
>>>>>> Actually we are just reading one byte, and priority changes while
>>>>>> interrupts are handled are a benign race that can happen on real
>>>>>> hardware
>>>>>> too. So it is safe to just prevent the compiler from reading from the
>>>>>> struct more than once.
>>>>>>
>>>>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>>>>> ---
>>>>>>   xen/arch/arm/vgic-v2.c | 13 ++++++++-----
>>>>>>   xen/arch/arm/vgic-v3.c | 11 +++++++----
>>>>>>   xen/arch/arm/vgic.c    |  8 +-------
>>>>>>   3 files changed, 16 insertions(+), 16 deletions(-)
>>>>>>
>>>>>> diff --git a/xen/arch/arm/vgic-v2.c b/xen/arch/arm/vgic-v2.c
>>>>>> index dc9f95b..5370020 100644
>>>>>> --- a/xen/arch/arm/vgic-v2.c
>>>>>> +++ b/xen/arch/arm/vgic-v2.c
>>>>>> @@ -258,9 +258,9 @@ static int vgic_v2_distr_mmio_read(struct vcpu
>>>>>> *v,
>>>>>> mmio_info_t *info,
>>>>>>           if ( rank == NULL ) goto read_as_zero;
>>>>>>
>>>>>>           vgic_lock_rank(v, rank, flags);
>>>>>> -        ipriorityr = rank->ipriorityr[REG_RANK_INDEX(8,
>>>>>> -                                                     gicd_reg -
>>>>>> GICD_IPRIORITYR,
>>>>>> -                                                     DABT_WORD)];
>>>>>> +        ipriorityr = ACCESS_ONCE(rank->ipriorityr[REG_RANK_INDEX(8,
>>>>>> +                                     gicd_reg - GICD_IPRIORITYR,
>>>>>> +                                     DABT_WORD)]);
>>>>>
>>>>> The indentation is a bit odd. Can you introduce a temporary
>>>>> variable here?
>>>>>
>>>>>>           vgic_unlock_rank(v, rank, flags);
>>>>>>           *r = vgic_reg32_extract(ipriorityr, info);
>>>>>>
>>>>>> @@ -499,7 +499,7 @@ static int vgic_v2_distr_mmio_write(struct
>>>>>> vcpu *v,
>>>>>> mmio_info_t *info,
>>>>>>
>>>>>>       case VRANGE32(GICD_IPRIORITYR, GICD_IPRIORITYRN):
>>>>>>       {
>>>>>> -        uint32_t *ipriorityr;
>>>>>> +        uint32_t *ipriorityr, priority;
>>>>>>
>>>>>>           if ( dabt.size != DABT_BYTE && dabt.size != DABT_WORD )
>>>>>> goto
>>>>>> bad_width;
>>>>>>           rank = vgic_rank_offset(v, 8, gicd_reg - GICD_IPRIORITYR,
>>>>>> DABT_WORD);
>>>>>> @@ -508,7 +508,10 @@ static int vgic_v2_distr_mmio_write(struct
>>>>>> vcpu *v,
>>>>>> mmio_info_t *info,
>>>>>>           ipriorityr = &rank->ipriorityr[REG_RANK_INDEX(8,
>>>>>>                                                         gicd_reg -
>>>>>> GICD_IPRIORITYR,
>>>>>>                                                         DABT_WORD)];
>>>>>> -        vgic_reg32_update(ipriorityr, r, info);
>>>>>> +        priority = ACCESS_ONCE(*ipriorityr);
>>>>>> +        vgic_reg32_update(&priority, r, info);
>>>>>> +        ACCESS_ONCE(*ipriorityr) = priority;
>>>>>
>>>>> This is a bit odd to read because of the dereferencing. I admit that I
>>>>> would
>>>>> prefer if you use read_atomic/write_atomic which are easier to
>>>>> understand
>>>>> (though the naming is confusing).
>>>>>
>>>>> Let see what Stefano thinks here.
>>>>
>>>> I also prefer *_atomic, especially given what Jan wrote about
>>>> ACCESS_ONCE:
>>>>
>>>>    Plus ACCESS_ONCE() doesn't enforce a single instruction to be
>>>> used in
>>>>    the resulting assembly).
>>>
>>> I don't buy this argument. There are quite a few places we rely on
>>> assignment
>>> to be atomic (see PV protocols for instance).
>>
>> I don't understand your explanation. There are no PV protocols under
>> xen/, they are implemented in other repositories. I grepped for ACCESS
>> under xen/include/public, in case you referred to the PV protocol
>> headers, but couldn't find anything interesting.
> 
> Have a look at the pl011 emulation from Bhupinder. It will use plain '='
> for updating the PV drivers. So can you explain why it is fine there and
> not here?
> 
>>
>>
>>> Furthermore implementation of
>>> atomic_read/atomic_write in Linux (both ARM and x86) is based on
>>> WRITE_ONCE/READ_ONCE, on Xen it is a simple assignment.
>>
>> I don't follow why you are referring to Linux constructs in this
>> discussion about Xen atomic functions.
> 
> My point here is Xen and Linux are very similar. Actually a lot of the
> atomic code is been taken from Linux (have a look to our
> atomic_read/atomic_write).
> 
> As the atomic code was added the code by you (likely from Linux), I
> don't understand why you don't complain about the atomic implementation
> but ACCESS_ONCE.
> 
>>
>>
>>> In any case, all those macros does not prevent re-ordering at the
>>> processor
>>> level nor read/write atomicity if the variable is misaligned.
>>
>> My understanding is that the unwritten assumption in Xen is that
>> variables are always aligned. You are right about processor level
>> reordering, in fact when needed we have to have barriers
>>
>> I have read Andre's well written README.atomic, and he ends the
>> document stating the following:
>>
>>
>>> This makes read and write accesses to ints and longs (and their
>>> respective
>>> unsigned counter parts) naturally atomic.
>>> However it would be beneficial to use atomic primitives anyway to
>>> annotate
>>> the code as being concurrent and to prevent silent breakage when
>>> changing
>>> the code
>>
>> with which I completely agree
> 
> Which means you are happy to use either ACCESS_ONCE or
> read_atomic/write_atomic as they in-fine exactly the same on the
> compiler we support.

So I think in this case it's not the same.
read_atomic() would prevent the compiler from breaking up the assignment
into multiple reads, which indeed does not seem necessary here (as it is
aligned, especially due to being a member of an array).
But we have to prevent the compiler from reading the variable *multiple
times* (with the value possibly changing in-between), so ACCESS_ONCE()
is needed, IMHO. It is beyond me to see through how the
vgic_reg32_extract/vgic_reg32_update macro expansion actually ends up,
but I reckon the compiler can break this up and inline it and would be
*allowed* to dereference the pointer several times.
Having said this, in practise it may not be relevant though, as the
compiler probably will only read it once anyway, because a read is
deemed comparably expensive and there is hardly any register pressure on
arm64. But for documenting that this is a lockless read outside of the
lock I'd rather have some annotation in the code.

As for the readability argument of "ACCESS_ONCE(*ptr) = foo;":
I agree, but was wondering why we don't have Linux' READ_ONCE/WRITE_ONCE
pairs in the first place. I see that the implementation of them is
nicely merged into one macro, but maybe we should have wrappers to
improve readability? Not sure that's something for this patch, though.
So can we postpone this for the rework? This will be touched anyway
because it's dealing with a rank.

Cheers,
Andre.

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* Re: [PATCH v11 01/34] ARM: vGIC: avoid rank lock when reading priority
  2017-06-14 11:22             ` Andre Przywara
@ 2017-06-14 11:27               ` Julien Grall
  0 siblings, 0 replies; 71+ messages in thread
From: Julien Grall @ 2017-06-14 11:27 UTC (permalink / raw)
  To: Andre Przywara, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi



On 06/14/2017 12:22 PM, Andre Przywara wrote:
> As for the readability argument of "ACCESS_ONCE(*ptr) = foo;":
> I agree, but was wondering why we don't have Linux' READ_ONCE/WRITE_ONCE
> pairs in the first place. I see that the implementation of them is
> nicely merged into one macro, but maybe we should have wrappers to
> improve readability? Not sure that's something for this patch, though.
> So can we postpone this for the rework? This will be touched anyway
> because it's dealing with a rank.

I think nobody looked at importing WRITE_ONCE/READ_ONCE on Xen. Feel 
free to send a patch :).

Anyway, I am happy to postpone for the rework.

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* Re: [PATCH v11 10/34] ARM: GIC: export and extend vgic_init_pending_irq()
  2017-06-12 15:36   ` Julien Grall
@ 2017-06-14 15:54     ` Andre Przywara
  2017-06-14 16:33       ` Julien Grall
  0 siblings, 1 reply; 71+ messages in thread
From: Andre Przywara @ 2017-06-14 15:54 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

Hi,

On 12/06/17 16:36, Julien Grall wrote:
> Hi Andre,
> 
> On 09/06/17 18:41, Andre Przywara wrote:
>> For LPIs we later want to dynamically allocate struct pending_irqs.
>> So beside needing to initialize the struct from there we also need
>> to clean it up and re-initialize it later on.
>> Export vgic_init_pending_irq() and extend it to be reusable.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>  xen/arch/arm/vgic.c        | 4 +++-
>>  xen/include/asm-arm/vgic.h | 1 +
>>  2 files changed, 4 insertions(+), 1 deletion(-)
>>
>> diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
>> index 2e4820f..7e8dba6 100644
>> --- a/xen/arch/arm/vgic.c
>> +++ b/xen/arch/arm/vgic.c
>> @@ -60,8 +60,10 @@ struct vgic_irq_rank *vgic_rank_irq(struct vcpu *v,
>> unsigned int irq)
>>      return vgic_get_rank(v, rank);
>>  }
>>
>> -static void vgic_init_pending_irq(struct pending_irq *p, unsigned int
>> virq)
>> +void vgic_init_pending_irq(struct pending_irq *p, unsigned int virq)
>>  {
>> +    memset(p, 0, sizeof(*p));
> 
> So for initialization, we will clear the memory twice which looks rather
> pointless (see the current caller).
> 
> We probably to drop the memset or replace xzalloc by xalloc in the
> caller. I would be ok to see this change in a follow-up patch. Assuming
> you will sent a patch:

So I checked the callers and now moved the memset from here to
its_discard_event(), just before the call to vgic_init_pending_irq().
That should be safe, because:
1) For the existing code (initialising SGIs/PPIs and SPIs) we always
zero pending_irq anyway, either by xzalloc or by an explicit memset.
2) The call in its_discard_event() has now an explicit memset before the
call.
3) Allocating struct pending_irqs for LPI upon mapping a device already
uses xzalloc, so they are initially zeroed. Before we re-use a struct,
we call its_discard_event(), which zeroes it as described in 2)

So I merged the change (remove memset here, put it in
its_discard_event()) into the new series.
Please tell me if that is too dangerous and I can back it out again.

Cheers,
Andre.

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* Re: [PATCH v11 10/34] ARM: GIC: export and extend vgic_init_pending_irq()
  2017-06-14 15:54     ` Andre Przywara
@ 2017-06-14 16:33       ` Julien Grall
  0 siblings, 0 replies; 71+ messages in thread
From: Julien Grall @ 2017-06-14 16:33 UTC (permalink / raw)
  To: Andre Przywara, Stefano Stabellini
  Cc: xen-devel, Vijaya Kumar K, Vijay Kilari, Shanker Donthineni,
	Manish Jaggi

Hi Andre,

On 06/14/2017 04:54 PM, Andre Przywara wrote:
> Hi,
> 
> On 12/06/17 16:36, Julien Grall wrote:
>> Hi Andre,
>>
>> On 09/06/17 18:41, Andre Przywara wrote:
>>> For LPIs we later want to dynamically allocate struct pending_irqs.
>>> So beside needing to initialize the struct from there we also need
>>> to clean it up and re-initialize it later on.
>>> Export vgic_init_pending_irq() and extend it to be reusable.
>>>
>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>> ---
>>>   xen/arch/arm/vgic.c        | 4 +++-
>>>   xen/include/asm-arm/vgic.h | 1 +
>>>   2 files changed, 4 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
>>> index 2e4820f..7e8dba6 100644
>>> --- a/xen/arch/arm/vgic.c
>>> +++ b/xen/arch/arm/vgic.c
>>> @@ -60,8 +60,10 @@ struct vgic_irq_rank *vgic_rank_irq(struct vcpu *v,
>>> unsigned int irq)
>>>       return vgic_get_rank(v, rank);
>>>   }
>>>
>>> -static void vgic_init_pending_irq(struct pending_irq *p, unsigned int
>>> virq)
>>> +void vgic_init_pending_irq(struct pending_irq *p, unsigned int virq)
>>>   {
>>> +    memset(p, 0, sizeof(*p));
>>
>> So for initialization, we will clear the memory twice which looks rather
>> pointless (see the current caller).
>>
>> We probably to drop the memset or replace xzalloc by xalloc in the
>> caller. I would be ok to see this change in a follow-up patch. Assuming
>> you will sent a patch:
> 
> So I checked the callers and now moved the memset from here to
> its_discard_event(), just before the call to vgic_init_pending_irq().
> That should be safe, because:
> 1) For the existing code (initialising SGIs/PPIs and SPIs) we always
> zero pending_irq anyway, either by xzalloc or by an explicit memset.
> 2) The call in its_discard_event() has now an explicit memset before the
> call.
> 3) Allocating struct pending_irqs for LPI upon mapping a device already
> uses xzalloc, so they are initially zeroed. Before we re-use a struct,
> we call its_discard_event(), which zeroes it as described in 2)

The place I am the most concerned is in the MAPTI. Because you would 
call vgic_init_pending_irq assuming this would have already been zeroed. 
It is not straight-forward when looking at the code who did that.

I would prefer to keep the memset in vgic_init_pending_irq and avoid it 
in the caller. This is more future proof.

> So I merged the change (remove memset here, put it in
> its_discard_event()) into the new series.
> Please tell me if that is too dangerous and I can back it out again.
Let's look for a follow-up patch and not in this series. I don't want to 
delay the series just for that.

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* Re: [PATCH v11 01/34] ARM: vGIC: avoid rank lock when reading priority
  2017-06-14  8:55           ` Julien Grall
  2017-06-14 11:22             ` Andre Przywara
@ 2017-06-14 17:32             ` Stefano Stabellini
  2017-06-14 17:44               ` Julien Grall
  1 sibling, 1 reply; 71+ messages in thread
From: Stefano Stabellini @ 2017-06-14 17:32 UTC (permalink / raw)
  To: Julien Grall
  Cc: Stefano Stabellini, Vijay Kilari, Manish Jaggi, Andre Przywara,
	Vijaya Kumar K, xen-devel, nd, Shanker Donthineni

On Wed, 14 Jun 2017, Julien Grall wrote:
> On 06/13/2017 11:19 PM, Stefano Stabellini wrote:
> > On Tue, 13 Jun 2017, Julien Grall wrote:
> > > On 12/06/2017 23:34, Stefano Stabellini wrote:
> > > > On Mon, 12 Jun 2017, Julien Grall wrote:
> > > > > Hi Andre,
> > > > > 
> > > > > On 09/06/17 18:41, Andre Przywara wrote:
> > > > > > When reading the priority value of a virtual interrupt, we were
> > > > > > taking
> > > > > > the respective rank lock so far.
> > > > > > However for forwarded interrupts (Dom0 only so far) this may lead to
> > > > > > a
> > > > > > deadlock with the following call chain:
> > > > > > - MMIO access to change the IRQ affinity, calling the ITARGETSR
> > > > > > handler
> > > > > > - this handler takes the appropriate rank lock and calls
> > > > > > vgic_store_itargetsr()
> > > > > > - vgic_store_itargetsr() will eventually call vgic_migrate_irq()
> > > > > > - if this IRQ is already in-flight, it will remove it from the old
> > > > > >    VCPU and inject it into the new one, by calling
> > > > > > vgic_vcpu_inject_irq()
> > > > > > - vgic_vcpu_inject_irq will call vgic_get_virq_priority()
> > > > > > - vgic_get_virq_priority() tries to take the rank lock - again!
> > > > > > It seems like this code path has never been exercised before.
> > > > > > 
> > > > > > Fix this by avoiding taking the lock in vgic_get_virq_priority()
> > > > > > (like
> > > > > > we
> > > > > > do in vgic_get_target_vcpu()).
> > > > > > Actually we are just reading one byte, and priority changes while
> > > > > > interrupts are handled are a benign race that can happen on real
> > > > > > hardware
> > > > > > too. So it is safe to just prevent the compiler from reading from
> > > > > > the
> > > > > > struct more than once.
> > > > > > 
> > > > > > Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> > > > > > ---
> > > > > >   xen/arch/arm/vgic-v2.c | 13 ++++++++-----
> > > > > >   xen/arch/arm/vgic-v3.c | 11 +++++++----
> > > > > >   xen/arch/arm/vgic.c    |  8 +-------
> > > > > >   3 files changed, 16 insertions(+), 16 deletions(-)
> > > > > > 
> > > > > > diff --git a/xen/arch/arm/vgic-v2.c b/xen/arch/arm/vgic-v2.c
> > > > > > index dc9f95b..5370020 100644
> > > > > > --- a/xen/arch/arm/vgic-v2.c
> > > > > > +++ b/xen/arch/arm/vgic-v2.c
> > > > > > @@ -258,9 +258,9 @@ static int vgic_v2_distr_mmio_read(struct vcpu
> > > > > > *v,
> > > > > > mmio_info_t *info,
> > > > > >           if ( rank == NULL ) goto read_as_zero;
> > > > > > 
> > > > > >           vgic_lock_rank(v, rank, flags);
> > > > > > -        ipriorityr = rank->ipriorityr[REG_RANK_INDEX(8,
> > > > > > -                                                     gicd_reg -
> > > > > > GICD_IPRIORITYR,
> > > > > > -                                                     DABT_WORD)];
> > > > > > +        ipriorityr = ACCESS_ONCE(rank->ipriorityr[REG_RANK_INDEX(8,
> > > > > > +                                     gicd_reg - GICD_IPRIORITYR,
> > > > > > +                                     DABT_WORD)]);
> > > > > 
> > > > > The indentation is a bit odd. Can you introduce a temporary variable
> > > > > here?
> > > > > 
> > > > > >           vgic_unlock_rank(v, rank, flags);
> > > > > >           *r = vgic_reg32_extract(ipriorityr, info);
> > > > > > 
> > > > > > @@ -499,7 +499,7 @@ static int vgic_v2_distr_mmio_write(struct vcpu
> > > > > > *v,
> > > > > > mmio_info_t *info,
> > > > > > 
> > > > > >       case VRANGE32(GICD_IPRIORITYR, GICD_IPRIORITYRN):
> > > > > >       {
> > > > > > -        uint32_t *ipriorityr;
> > > > > > +        uint32_t *ipriorityr, priority;
> > > > > > 
> > > > > >           if ( dabt.size != DABT_BYTE && dabt.size != DABT_WORD )
> > > > > > goto
> > > > > > bad_width;
> > > > > >           rank = vgic_rank_offset(v, 8, gicd_reg - GICD_IPRIORITYR,
> > > > > > DABT_WORD);
> > > > > > @@ -508,7 +508,10 @@ static int vgic_v2_distr_mmio_write(struct vcpu
> > > > > > *v,
> > > > > > mmio_info_t *info,
> > > > > >           ipriorityr = &rank->ipriorityr[REG_RANK_INDEX(8,
> > > > > >                                                         gicd_reg -
> > > > > > GICD_IPRIORITYR,
> > > > > >                                                         DABT_WORD)];
> > > > > > -        vgic_reg32_update(ipriorityr, r, info);
> > > > > > +        priority = ACCESS_ONCE(*ipriorityr);
> > > > > > +        vgic_reg32_update(&priority, r, info);
> > > > > > +        ACCESS_ONCE(*ipriorityr) = priority;
> > > > > 
> > > > > This is a bit odd to read because of the dereferencing. I admit that I
> > > > > would
> > > > > prefer if you use read_atomic/write_atomic which are easier to
> > > > > understand
> > > > > (though the naming is confusing).
> > > > > 
> > > > > Let see what Stefano thinks here.
> > > > 
> > > > I also prefer *_atomic, especially given what Jan wrote about
> > > > ACCESS_ONCE:
> > > > 
> > > >    Plus ACCESS_ONCE() doesn't enforce a single instruction to be used in
> > > >    the resulting assembly).
> > > 
> > > I don't buy this argument. There are quite a few places we rely on
> > > assignment
> > > to be atomic (see PV protocols for instance).
> > 
> > I don't understand your explanation. There are no PV protocols under
> > xen/, they are implemented in other repositories. I grepped for ACCESS
> > under xen/include/public, in case you referred to the PV protocol
> > headers, but couldn't find anything interesting.
> 
> Have a look at the pl011 emulation from Bhupinder. It will use plain '=' for
> updating the PV drivers. So can you explain why it is fine there and not here?

Bhupinder's series is the first PV driver in the Xen codebase. It is
easy to forget that coding should/might have to be different compared to
Linux, which is the codebase I usually work with for PV drivers.

It is true that updating the indexes should be done atomically,
otherwise the other end might end up reading a wrong index value.


> > > Furthermore implementation of
> > > atomic_read/atomic_write in Linux (both ARM and x86) is based on
> > > WRITE_ONCE/READ_ONCE, on Xen it is a simple assignment.
> > 
> > I don't follow why you are referring to Linux constructs in this
> > discussion about Xen atomic functions.
> 
> My point here is Xen and Linux are very similar. Actually a lot of the atomic
> code is been taken from Linux (have a look to our atomic_read/atomic_write).
> 
> As the atomic code was added the code by you (likely from Linux), I don't
> understand why you don't complain about the atomic implementation but
> ACCESS_ONCE.

Linux and Xen are free to make different assumptions regarding
compilers.

FWIW I am not really complaining about either atomics or ACCESS_ONCE, I
just don't see the advantage of using ACCESS_ONCE over read/write_atomic
(see below).


> > > In any case, all those macros does not prevent re-ordering at the
> > > processor
> > > level nor read/write atomicity if the variable is misaligned.
> > 
> > My understanding is that the unwritten assumption in Xen is that
> > variables are always aligned. You are right about processor level
> > reordering, in fact when needed we have to have barriers
> > 
> > I have read Andre's well written README.atomic, and he ends the
> > document stating the following:
> > 
> > 
> > > This makes read and write accesses to ints and longs (and their respective
> > > unsigned counter parts) naturally atomic.
> > > However it would be beneficial to use atomic primitives anyway to annotate
> > > the code as being concurrent and to prevent silent breakage when changing
> > > the code
> > 
> > with which I completely agree
> 
> Which means you are happy to use either ACCESS_ONCE or
> read_atomic/write_atomic as they in-fine exactly the same on the compiler we
> support.

I do understand that both of them will produce the same output,
therefore, both work for this use-case.

I don't understand why anybody would prefer ACCESS_ONCE over
read/write_atomic, given that with ACCESS_ONCE as a contributor/reviewer
you additionally need to remember to check whether the argument is a
native data type. Basically, I see ACCESS_ONCE as "more work" for me.
Why do you think that ACCESS_ONCE is "better"?

Regarding the "compiler with support": do we state clearly in any docs
or website what are the compilers we support? I think this would be the
right opportunity to do it.

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* Re: [PATCH v11 01/34] ARM: vGIC: avoid rank lock when reading priority
  2017-06-14 17:32             ` Stefano Stabellini
@ 2017-06-14 17:44               ` Julien Grall
  2017-06-14 18:15                 ` Stefano Stabellini
  0 siblings, 1 reply; 71+ messages in thread
From: Julien Grall @ 2017-06-14 17:44 UTC (permalink / raw)
  To: Stefano Stabellini
  Cc: Vijay Kilari, Manish Jaggi, Andre Przywara, Vijaya Kumar K,
	xen-devel, nd, Shanker Donthineni

Hi Stefano,

On 06/14/2017 06:32 PM, Stefano Stabellini wrote:
> On Wed, 14 Jun 2017, Julien Grall wrote:
>>> I don't understand your explanation. There are no PV protocols under
>>> xen/, they are implemented in other repositories. I grepped for ACCESS
>>> under xen/include/public, in case you referred to the PV protocol
>>> headers, but couldn't find anything interesting.
>>
>> Have a look at the pl011 emulation from Bhupinder. It will use plain '=' for
>> updating the PV drivers. So can you explain why it is fine there and not here?
> 
> Bhupinder's series is the first PV driver in the Xen codebase. It is
> easy to forget that coding should/might have to be different compared to
> Linux, which is the codebase I usually work with for PV drivers.
> 
> It is true that updating the indexes should be done atomically,
> otherwise the other end might end up reading a wrong index value.
> 
> 
>>>> Furthermore implementation of
>>>> atomic_read/atomic_write in Linux (both ARM and x86) is based on
>>>> WRITE_ONCE/READ_ONCE, on Xen it is a simple assignment.
>>>
>>> I don't follow why you are referring to Linux constructs in this
>>> discussion about Xen atomic functions.
>>
>> My point here is Xen and Linux are very similar. Actually a lot of the atomic
>> code is been taken from Linux (have a look to our atomic_read/atomic_write).
>>
>> As the atomic code was added the code by you (likely from Linux), I don't
>> understand why you don't complain about the atomic implementation but
>> ACCESS_ONCE.
> 
> Linux and Xen are free to make different assumptions regarding
> compilers.

It is not possible to say that Xen may have different assumptions when 
you import code from Linux without deep review (yes most of the code 
taken from Linux is as it is).

> 
> FWIW I am not really complaining about either atomics or ACCESS_ONCE, I
> just don't see the advantage of using ACCESS_ONCE over read/write_atomic
> (see below).
> 
> 
>>>> In any case, all those macros does not prevent re-ordering at the
>>>> processor
>>>> level nor read/write atomicity if the variable is misaligned.
>>>
>>> My understanding is that the unwritten assumption in Xen is that
>>> variables are always aligned. You are right about processor level
>>> reordering, in fact when needed we have to have barriers
>>>
>>> I have read Andre's well written README.atomic, and he ends the
>>> document stating the following:
>>>
>>>
>>>> This makes read and write accesses to ints and longs (and their respective
>>>> unsigned counter parts) naturally atomic.
>>>> However it would be beneficial to use atomic primitives anyway to annotate
>>>> the code as being concurrent and to prevent silent breakage when changing
>>>> the code
>>>
>>> with which I completely agree
>>
>> Which means you are happy to use either ACCESS_ONCE or
>> read_atomic/write_atomic as they in-fine exactly the same on the compiler we
>> support.
> 
> I do understand that both of them will produce the same output,
> therefore, both work for this use-case.
> 
> I don't understand why anybody would prefer ACCESS_ONCE over
> read/write_atomic, given that with ACCESS_ONCE as a contributor/reviewer
> you additionally need to remember to check whether the argument is a
> native data type. Basically, I see ACCESS_ONCE as "more work" for me.
> Why do you think that ACCESS_ONCE is "better"?

Have you looked at the implementation of ACCESS_ONCE? You don't have to 
check the data type when using ACCESS_ONCE. There are safety check to 
avoid misusing it.

What I want to avoid is this split mind we currently have about atomic.
They are either all safe or not.

As Andre suggested, we should probably import a lighter version of 
WRITE_ONCE/READ_ONCE. They are first easier to understand than 
read_atomic/write_atomic that could be confused with 
atomic_read/atomic_write (IIRC Jan agreed here).

The main goal is to avoid assembly code when it is deem not necessary.

> 
> Regarding the "compiler with support": do we state clearly in any docs
> or website what are the compilers we support? I think this would be the
> right opportunity to do it.

That's a discussion to have on the README.atomics patch.

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* Re: [PATCH v11 01/34] ARM: vGIC: avoid rank lock when reading priority
  2017-06-14 17:44               ` Julien Grall
@ 2017-06-14 18:15                 ` Stefano Stabellini
  2017-06-14 18:32                   ` Julien Grall
  0 siblings, 1 reply; 71+ messages in thread
From: Stefano Stabellini @ 2017-06-14 18:15 UTC (permalink / raw)
  To: Julien Grall
  Cc: Stefano Stabellini, Vijay Kilari, Manish Jaggi, Andre Przywara,
	Vijaya Kumar K, xen-devel, nd, Shanker Donthineni

On Wed, 14 Jun 2017, Julien Grall wrote:
> > > > > In any case, all those macros does not prevent re-ordering at the
> > > > > processor
> > > > > level nor read/write atomicity if the variable is misaligned.
> > > > 
> > > > My understanding is that the unwritten assumption in Xen is that
> > > > variables are always aligned. You are right about processor level
> > > > reordering, in fact when needed we have to have barriers
> > > > 
> > > > I have read Andre's well written README.atomic, and he ends the
> > > > document stating the following:
> > > > 
> > > > 
> > > > > This makes read and write accesses to ints and longs (and their
> > > > > respective
> > > > > unsigned counter parts) naturally atomic.
> > > > > However it would be beneficial to use atomic primitives anyway to
> > > > > annotate
> > > > > the code as being concurrent and to prevent silent breakage when
> > > > > changing
> > > > > the code
> > > > 
> > > > with which I completely agree
> > > 
> > > Which means you are happy to use either ACCESS_ONCE or
> > > read_atomic/write_atomic as they in-fine exactly the same on the compiler
> > > we
> > > support.
> > 
> > I do understand that both of them will produce the same output,
> > therefore, both work for this use-case.
> > 
> > I don't understand why anybody would prefer ACCESS_ONCE over
> > read/write_atomic, given that with ACCESS_ONCE as a contributor/reviewer
> > you additionally need to remember to check whether the argument is a
> > native data type. Basically, I see ACCESS_ONCE as "more work" for me.
> > Why do you think that ACCESS_ONCE is "better"?
> 
> Have you looked at the implementation of ACCESS_ONCE? You don't have to check
> the data type when using ACCESS_ONCE. There are safety check to avoid misusing
> it.

It checks for a scalar type, not for native data type. They are not
always the same thing but I think they are on arm.


> What I want to avoid is this split mind we currently have about atomic.
> They are either all safe or not.

What split mind? Do you mean ACCESS_ONCE vs. read/write_atomic? So far,
there are no instances of ACCESS_ONCE in xen/arch/arm.


> As Andre suggested, we should probably import a lighter version of
> WRITE_ONCE/READ_ONCE. They are first easier to understand than
> read_atomic/write_atomic that could be confused with atomic_read/atomic_write
> (IIRC Jan agreed here).
> 
> The main goal is to avoid assembly code when it is deem not necessary.

All right, this is one reason. Sorry if I seem unnecessarily contrarian,
but this is the first time I read a reason for this recent push for using
ACCESS_ONCE. You wrote that you preferred the read/write_atomic
functions yourself on Monday.

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

* Re: [PATCH v11 01/34] ARM: vGIC: avoid rank lock when reading priority
  2017-06-14 18:15                 ` Stefano Stabellini
@ 2017-06-14 18:32                   ` Julien Grall
  0 siblings, 0 replies; 71+ messages in thread
From: Julien Grall @ 2017-06-14 18:32 UTC (permalink / raw)
  To: Stefano Stabellini
  Cc: Vijay Kilari, Manish Jaggi, Andre Przywara, Vijaya Kumar K,
	xen-devel, nd, Shanker Donthineni

Hi Stefano,

On 06/14/2017 07:15 PM, Stefano Stabellini wrote:
> On Wed, 14 Jun 2017, Julien Grall wrote:
>>>>>> In any case, all those macros does not prevent re-ordering at the
>>>>>> processor
>>>>>> level nor read/write atomicity if the variable is misaligned.
>>>>>
>>>>> My understanding is that the unwritten assumption in Xen is that
>>>>> variables are always aligned. You are right about processor level
>>>>> reordering, in fact when needed we have to have barriers
>>>>>
>>>>> I have read Andre's well written README.atomic, and he ends the
>>>>> document stating the following:
>>>>>
>>>>>
>>>>>> This makes read and write accesses to ints and longs (and their
>>>>>> respective
>>>>>> unsigned counter parts) naturally atomic.
>>>>>> However it would be beneficial to use atomic primitives anyway to
>>>>>> annotate
>>>>>> the code as being concurrent and to prevent silent breakage when
>>>>>> changing
>>>>>> the code
>>>>>
>>>>> with which I completely agree
>>>>
>>>> Which means you are happy to use either ACCESS_ONCE or
>>>> read_atomic/write_atomic as they in-fine exactly the same on the compiler
>>>> we
>>>> support.
>>>
>>> I do understand that both of them will produce the same output,
>>> therefore, both work for this use-case.
>>>
>>> I don't understand why anybody would prefer ACCESS_ONCE over
>>> read/write_atomic, given that with ACCESS_ONCE as a contributor/reviewer
>>> you additionally need to remember to check whether the argument is a
>>> native data type. Basically, I see ACCESS_ONCE as "more work" for me.
>>> Why do you think that ACCESS_ONCE is "better"?
>>
>> Have you looked at the implementation of ACCESS_ONCE? You don't have to check
>> the data type when using ACCESS_ONCE. There are safety check to avoid misusing
>> it.
> 
> It checks for a scalar type, not for native data type. They are not
> always the same thing but I think they are on arm.
That's the goal of specification (such as AAPCS).

>> What I want to avoid is this split mind we currently have about atomic.
>> They are either all safe or not.
> 
> What split mind? Do you mean ACCESS_ONCE vs. read/write_atomic? So far,
> there are no instances of ACCESS_ONCE in xen/arch/arm.

No. I mean there are places with exact same construct but sometimes 
consider we consider safe, sometimes not. We should have a clear common 
answer rather than arguing differently every time.

>> As Andre suggested, we should probably import a lighter version of
>> WRITE_ONCE/READ_ONCE. They are first easier to understand than
>> read_atomic/write_atomic that could be confused with atomic_read/atomic_write
>> (IIRC Jan agreed here).
>>
>> The main goal is to avoid assembly code when it is deem not necessary.
> 
> All right, this is one reason. Sorry if I seem unnecessarily contrarian,
> but this is the first time I read a reason for this recent push for using
> ACCESS_ONCE. You wrote that you preferred the read/write_atomic
> functions yourself on Monday.

I preferred {read,write}_atomic because the prototype is nicer to use 
than ACCESS_ONCE. In the ideal we should introduce WRITE_ONCE/READ_ONCE 
improving the naming and also having a nice prototype.

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

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

end of thread, other threads:[~2017-06-14 18:32 UTC | newest]

Thread overview: 71+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-06-09 17:41 [PATCH v11 00/34] arm64: Dom0 ITS emulation Andre Przywara
2017-06-09 17:41 ` [PATCH v11 01/34] ARM: vGIC: avoid rank lock when reading priority Andre Przywara
2017-06-12 14:49   ` Julien Grall
2017-06-12 22:34     ` Stefano Stabellini
2017-06-13  9:01       ` Julien Grall
2017-06-13 22:19         ` Stefano Stabellini
2017-06-14  8:55           ` Julien Grall
2017-06-14 11:22             ` Andre Przywara
2017-06-14 11:27               ` Julien Grall
2017-06-14 17:32             ` Stefano Stabellini
2017-06-14 17:44               ` Julien Grall
2017-06-14 18:15                 ` Stefano Stabellini
2017-06-14 18:32                   ` Julien Grall
2017-06-09 17:41 ` [PATCH v11 02/34] ARM: GICv3: enable ITS on the host Andre Przywara
2017-06-12 14:51   ` Julien Grall
2017-06-09 17:41 ` [PATCH v11 03/34] ARM: GICv3: enable LPIs " Andre Przywara
2017-06-09 17:41 ` [PATCH v11 04/34] ARM: GICv3: setup number of LPI bits for a GICv3 guest Andre Przywara
2017-06-12 15:03   ` Julien Grall
2017-06-09 17:41 ` [PATCH v11 05/34] ARM: vGIC: rework gic_remove_from_queues() Andre Przywara
2017-06-12 15:15   ` Julien Grall
2017-06-09 17:41 ` [PATCH v11 06/34] ARM: vGIC: move irq_to_pending() calls under the VGIC VCPU lock Andre Przywara
2017-06-12 15:22   ` Julien Grall
2017-06-12 22:43     ` Stefano Stabellini
2017-06-09 17:41 ` [PATCH v11 07/34] ARM: vGIC: introduce gic_remove_irq() Andre Przywara
2017-06-12 15:28   ` Julien Grall
2017-06-09 17:41 ` [PATCH v11 08/34] ARM: GIC: Add checks for NULL pointer pending_irq's Andre Przywara
2017-06-12 15:30   ` Julien Grall
2017-06-12 22:44   ` Stefano Stabellini
2017-06-09 17:41 ` [PATCH v11 09/34] ARM: GICv3: introduce separate pending_irq structs for LPIs Andre Przywara
2017-06-09 17:41 ` [PATCH v11 10/34] ARM: GIC: export and extend vgic_init_pending_irq() Andre Przywara
2017-06-12 15:36   ` Julien Grall
2017-06-14 15:54     ` Andre Przywara
2017-06-14 16:33       ` Julien Grall
2017-06-09 17:41 ` [PATCH v11 11/34] ARM: vGIC: cache virtual LPI priority in struct pending_irq Andre Przywara
2017-06-12 15:39   ` Julien Grall
2017-06-09 17:41 ` [PATCH v11 12/34] ARM: vGIC: add LPI VCPU ID to " Andre Przywara
2017-06-12 15:46   ` Julien Grall
2017-06-09 17:41 ` [PATCH v11 13/34] ARM: GIC: ITS: remove no longer needed VCPU ID in host LPI entry Andre Przywara
2017-06-12 15:47   ` Julien Grall
2017-06-09 17:41 ` [PATCH v11 14/34] ARM: GICv3: forward pending LPIs to guests Andre Przywara
2017-06-12 15:53   ` Julien Grall
2017-06-09 17:41 ` [PATCH v11 15/34] ARM: vGICv3: handle virtual LPI pending and property tables Andre Przywara
2017-06-09 17:41 ` [PATCH v11 16/34] ARM: introduce vgic_access_guest_memory() Andre Przywara
2017-06-09 17:41 ` [PATCH v11 17/34] ARM: vGICv3: re-use vgic_reg64_check_access Andre Przywara
2017-06-09 17:41 ` [PATCH v11 18/34] ARM: vGIC: advertise LPI support Andre Przywara
2017-06-12 16:02   ` Julien Grall
2017-06-09 17:41 ` [PATCH v11 19/34] ARM: vITS: add command handling stub and MMIO emulation Andre Przywara
2017-06-12 16:04   ` Julien Grall
2017-06-09 17:41 ` [PATCH v11 20/34] ARM: vITS: introduce translation table walks Andre Przywara
2017-06-12 16:07   ` Julien Grall
2017-06-09 17:41 ` [PATCH v11 21/34] ARM: vITS: provide access to struct pending_irq Andre Przywara
2017-06-09 17:41 ` [PATCH v11 22/34] ARM: vITS: handle INT command Andre Przywara
2017-06-09 17:41 ` [PATCH v11 23/34] ARM: vITS: handle MAPC command Andre Przywara
2017-06-09 17:41 ` [PATCH v11 24/34] ARM: vITS: handle CLEAR command Andre Przywara
2017-06-12 16:19   ` Julien Grall
2017-06-09 17:41 ` [PATCH v11 25/34] ARM: vITS: handle MAPD command Andre Przywara
2017-06-13 22:02   ` Stefano Stabellini
2017-06-09 17:41 ` [PATCH v11 26/34] ARM: GICv3: handle unmapped LPIs Andre Przywara
2017-06-12 16:30   ` Julien Grall
2017-06-09 17:41 ` [PATCH v11 27/34] ARM: vITS: handle MAPTI/MAPI command Andre Przywara
2017-06-12 16:36   ` Julien Grall
2017-06-09 17:41 ` [PATCH v11 28/34] ARM: vITS: handle MOVI command Andre Przywara
2017-06-12 16:37   ` Julien Grall
2017-06-09 17:41 ` [PATCH v11 29/34] ARM: vITS: handle DISCARD command Andre Przywara
2017-06-09 17:41 ` [PATCH v11 30/34] ARM: vITS: handle INV command Andre Przywara
2017-06-09 17:41 ` [PATCH v11 31/34] ARM: vITS: handle INVALL command Andre Przywara
2017-06-12 16:41   ` Julien Grall
2017-06-09 17:41 ` [PATCH v11 32/34] ARM: vITS: increase mmio_count for each ITS Andre Przywara
2017-06-09 17:41 ` [PATCH v11 33/34] ARM: vITS: create and initialize virtual ITSes for Dom0 Andre Przywara
2017-06-09 17:41 ` [PATCH v11 34/34] ARM: vITS: create ITS subnodes for Dom0 DT Andre Przywara
2017-06-12  5:04 ` [PATCH v11 00/34] arm64: Dom0 ITS emulation Manish Jaggi

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.