[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen staging] xen/arm: gic: Ensure ordering between read of INTACK and shared data



commit 555e5f1bd26c4c1995357e9671b3e42a68d5ce8f
Author:     Julien Grall <julien.grall@xxxxxxx>
AuthorDate: Tue Oct 23 19:17:07 2018 +0100
Commit:     Stefano Stabellini <sstabellini@xxxxxxxxxx>
CommitDate: Fri Nov 9 15:10:17 2018 -0800

    xen/arm: gic: Ensure ordering between read of INTACK and shared data
    
    When an IPI is generated by a CPU, the pattern looks roughly like:
    
      <write shared data>
      dsb(sy);
      <write to GIC to signal SGI>
    
    On the receiving CPU we rely on the fact that, once we've taken the
    interrupt, then the freshly written shared data must be visible to us.
    Put another way, the CPU isn't going to speculate taking an interrupt.
    
    Unfortunately, this assumption turns out to be broken.
    
    Consider that CPUx wants to send an IPI to CPUy, which will cause CPUy
    to read some shared_data. Before CPUx has done anything, a random
    peripheral raises an IRQ to the GIC and the IRQ line on CPUy is raised.
    CPUy then takes the IRQ and starts executing the entry code, heading
    towards gic_handle_irq. Furthermore, let's assume that a bunch of the
    previous interrupts handled by CPUy were SGIs, so the branch predictor
    kicks in and speculates that irqnr will be <16 and we're likely to
    head into handle_IPI. The prefetcher then grabs a speculative copy of
    shared_data which contains a stale value.
    
    Meanwhile, CPUx gets round to updating shared_data and asking the GIC
    to send an SGI to CPUy. Internally, the GIC decides that the SGI is
    more important than the peripheral interrupt (which hasn't yet been
    ACKed) but doesn't need to do anything to CPUy, because the IRQ line
    is already raised.
    
    CPUy then reads the ACK register on the GIC, sees the SGI value which
    confirms the branch prediction and we end up with a stale shared_data
    value.
    
    This patch fixes the problem by adding an smp_rmb() to the IPI entry
    code in do_SGI.
    
    At the same time document the write barrier.
    
    Based on Linux commit f86c4fbd930ff6fecf3d8a1c313182bd0f49f496
    "irqchip/gic: Ensure ordering between read of INTACK and shared data".
    
    Signed-off-by: Julien Grall <julien.grall@xxxxxxx>
    Reviewed-by: Andrii Anisov<andrii_anisov@xxxxxxxx>
    Reviewed-by: Stefano Stabellini <sstabellini@xxxxxxxxxx>
---
 xen/arch/arm/gic.c | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index cb23b64cc9..baf74324e5 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -296,6 +296,11 @@ void send_SGI_mask(const cpumask_t *cpumask, enum gic_sgi 
sgi)
 {
     ASSERT(sgi < 16); /* There are only 16 SGIs */
 
+   /*
+    * Ensure that stores to Normal memory are visible to the other CPUs
+    * before issuing the IPI.
+    * Matches the read barrier in do_sgi.
+    */
     dsb(sy);
     gic_hw_ops->send_SGI(sgi, SGI_TARGET_LIST, cpumask);
 }
@@ -309,6 +314,11 @@ void send_SGI_self(enum gic_sgi sgi)
 {
     ASSERT(sgi < 16); /* There are only 16 SGIs */
 
+   /*
+    * Ensure that stores to Normal memory are visible to the other CPUs
+    * before issuing the IPI.
+    * Matches the read barrier in do_sgi.
+    */
     dsb(sy);
     gic_hw_ops->send_SGI(sgi, SGI_TARGET_SELF, NULL);
 }
@@ -317,6 +327,11 @@ void send_SGI_allbutself(enum gic_sgi sgi)
 {
    ASSERT(sgi < 16); /* There are only 16 SGIs */
 
+   /*
+    * Ensure that stores to Normal memory are visible to the other CPUs
+    * before issuing the IPI.
+    * Matches the read barrier in do_sgi.
+    */
    dsb(sy);
    gic_hw_ops->send_SGI(sgi, SGI_TARGET_OTHERS, NULL);
 }
@@ -352,6 +367,13 @@ static void do_sgi(struct cpu_user_regs *regs, enum 
gic_sgi sgi)
     /* Lower the priority */
     gic_hw_ops->eoi_irq(desc);
 
+    /*
+     * Ensure any shared data written by the CPU sending
+     * the IPI is read after we've read the ACK register on the GIC.
+     * Matches the write barrier in send_SGI_* helpers.
+     */
+    smp_rmb();
+
     switch (sgi)
     {
     case GIC_SGI_EVENT_CHECK:
--
generated by git-patchbot for /home/xen/git/xen.git#staging

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/xen-changelog

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.