From: Alexandru Elisei <alexandru.eli...@arm.com>

The psci test performs a series of CPU_ON/CPU_OFF cycles for CPU 1. This is
done by setting the entry point for the CPU_ON call to the physical address
of the C function cpu_psci_cpu_die.

The compiler is well within its rights to use the stack when generating
code for cpu_psci_cpu_die.  However, because no stack initialization has
been done, the stack pointer is zero, as set by KVM when creating the VCPU.
This causes a data abort without a change in exception level. The VBAR_EL1
register is also zero (the KVM reset value for VBAR_EL1), the MMU is off,
and we end up trying to fetch instructions from address 0x200.

At this point, a stage 2 instruction abort is generated which is taken to
KVM. KVM interprets this as an instruction fetch from an I/O region, and
injects a prefetch abort into the guest. Prefetch abort is a synchronous
exception, and on guest return the VCPU PC will be set to VBAR_EL1 + 0x200,
which is...  0x200. The VCPU ends up in an infinite loop causing a prefetch
abort while fetching the instruction to service the said abort.

To avoid all of this, lets use the assembly function halt as the CPU_ON
entry address. Also, expand the check to test that we only get
PSCI_RET_SUCCESS exactly once, as we're never offlining the CPU during the
test.

Signed-off-by: Alexandru Elisei <alexandru.eli...@arm.com>
Signed-off-by: Andrew Jones <drjo...@redhat.com>
---
 arm/psci.c | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/arm/psci.c b/arm/psci.c
index 5c1accb6cea4..ffc09a2e9858 100644
--- a/arm/psci.c
+++ b/arm/psci.c
@@ -79,13 +79,14 @@ static void cpu_on_secondary_entry(void)
        cpumask_set_cpu(cpu, &cpu_on_ready);
        while (!cpu_on_start)
                cpu_relax();
-       cpu_on_ret[cpu] = psci_cpu_on(cpus[1], __pa(cpu_psci_cpu_die));
+       cpu_on_ret[cpu] = psci_cpu_on(cpus[1], __pa(halt));
        cpumask_set_cpu(cpu, &cpu_on_done);
 }
 
 static bool psci_cpu_on_test(void)
 {
        bool failed = false;
+       int ret_success = 0;
        int cpu;
 
        cpumask_set_cpu(1, &cpu_on_ready);
@@ -104,7 +105,7 @@ static bool psci_cpu_on_test(void)
        cpu_on_start = 1;
        smp_mb();
 
-       cpu_on_ret[0] = psci_cpu_on(cpus[1], __pa(cpu_psci_cpu_die));
+       cpu_on_ret[0] = psci_cpu_on(cpus[1], __pa(halt));
        cpumask_set_cpu(0, &cpu_on_done);
 
        while (!cpumask_full(&cpu_on_done))
@@ -113,12 +114,19 @@ static bool psci_cpu_on_test(void)
        for_each_present_cpu(cpu) {
                if (cpu == 1)
                        continue;
-               if (cpu_on_ret[cpu] != PSCI_RET_SUCCESS && cpu_on_ret[cpu] != 
PSCI_RET_ALREADY_ON) {
+               if (cpu_on_ret[cpu] == PSCI_RET_SUCCESS) {
+                       ret_success++;
+               } else if (cpu_on_ret[cpu] != PSCI_RET_ALREADY_ON) {
                        report_info("unexpected cpu_on return value: 
caller=CPU%d, ret=%d", cpu, cpu_on_ret[cpu]);
                        failed = true;
                }
        }
 
+       if (ret_success != 1) {
+               report_info("got %d CPU_ON success", ret_success);
+               failed = true;
+       }
+
        return !failed;
 }
 
-- 
2.25.1

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

Reply via email to