We only handled routing mode 0 (filtered) and 1 (broadcast) so far, but
mode 0 incorrectly skipped the caller CPU as target. Mode 2 (self-SGI)
was completely ignored.

This rewrites gic_handle_sgir_write, addressing all 3 cases properly.

Signed-off-by: Jan Kiszka <jan.kis...@siemens.com>
---
 hypervisor/arch/arm/gic-common.c | 57 ++++++++++++++++++++++------------------
 1 file changed, 32 insertions(+), 25 deletions(-)

diff --git a/hypervisor/arch/arm/gic-common.c b/hypervisor/arch/arm/gic-common.c
index fec878b..18ebfeb 100644
--- a/hypervisor/arch/arm/gic-common.c
+++ b/hypervisor/arch/arm/gic-common.c
@@ -220,33 +220,40 @@ int gic_probe_cpu_id(unsigned int cpu)
 void gic_handle_sgir_write(struct sgi *sgi, bool virt_input)
 {
        struct per_cpu *cpu_data = this_cpu_data();
+       unsigned long targets = sgi->targets;
        unsigned int cpu;
-       unsigned long targets;
-       unsigned int this_cpu = cpu_data->cpu_id;
-       struct cell *cell = cpu_data->cell;
-       bool is_target = false;
 
-       targets = sgi->targets;
-       sgi->targets = 0;
-
-       /* Filter the targets */
-       for_each_cpu_except(cpu, cell->cpu_set, this_cpu) {
-               /*
-                * When using a cpu map to target the different CPUs (GICv2),
-                * they are independent from the physical CPU IDs, so there is
-                * no need to translate them to the hypervisor's virtual IDs.
-                */
-               if (virt_input)
-                       is_target = !!test_bit(arm_cpu_phys2virt(cpu),
-                                              &targets);
-               else
-                       is_target = !!(targets & target_cpu_map[cpu]);
-
-               if (sgi->routing_mode == 0 && !is_target)
-                       continue;
-
-               irqchip_set_pending(per_cpu(cpu), sgi->id);
-               sgi->targets |= (1 << cpu);
+       if (sgi->routing_mode == 2) {
+               /* Route to the caller itself */
+               irqchip_set_pending(cpu_data, sgi->id);
+               sgi->targets = (1 << cpu_data->cpu_id);
+       } else {
+               sgi->targets = 0;
+
+               for_each_cpu(cpu, cpu_data->cell->cpu_set) {
+                       if (sgi->routing_mode == 1) {
+                               /* Route to all (cell) CPUs but the caller. */
+                               if (cpu == cpu_data->cpu_id)
+                                       continue;
+                       } else if (virt_input) {
+                               if (!test_bit(arm_cpu_phys2virt(cpu),
+                                             &targets))
+                                       continue;
+                       } else {
+                               /*
+                                * When using a cpu map to target the different
+                                * CPUs (GICv2), they are independent from the
+                                * physical CPU IDs, so there is no need to
+                                * translate them to the hypervisor's virtual
+                                * IDs.
+                                */
+                               if (!(targets & target_cpu_map[cpu]))
+                                       continue;
+                       }
+
+                       irqchip_set_pending(per_cpu(cpu), sgi->id);
+                       sgi->targets |= (1 << cpu);
+               }
        }
 
        /* Let the other CPUS inject their SGIs */
-- 
2.1.4

-- 
You received this message because you are subscribed to the Google Groups 
"Jailhouse" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to jailhouse-dev+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to