From: Antonios Motakis <[email protected]>

Add hypervisor disable support to the Jailhouse firmware. Handle
Jailhouse disable calls from the root cell, and also disable the
hypervisor in case of an error during initialization.

Signed-off-by: Antonios Motakis <[email protected]>
---
 hypervisor/arch/arm64/control.c            |  8 +++++--
 hypervisor/arch/arm64/entry.S              | 33 +++++++++++++++++++++++++++
 hypervisor/arch/arm64/include/asm/percpu.h |  1 +
 hypervisor/arch/arm64/setup.c              | 36 ++++++++++++++++++++++++++++--
 hypervisor/arch/arm64/traps.c              |  4 ++++
 5 files changed, 78 insertions(+), 4 deletions(-)

diff --git a/hypervisor/arch/arm64/control.c b/hypervisor/arch/arm64/control.c
index 4b6643a..0e1c780 100644
--- a/hypervisor/arch/arm64/control.c
+++ b/hypervisor/arch/arm64/control.c
@@ -124,8 +124,12 @@ void arch_config_commit(struct cell *cell_added_removed)
 
 void arch_shutdown(void)
 {
-       trace_error(-EINVAL);
-       while (1);
+       unsigned int cpu;
+
+       /* turn off the hypervisor when we return from the exit handler */
+       if (root_cell.cpu_set)
+               for_each_cpu(cpu, root_cell.cpu_set)
+                       per_cpu(cpu)->shutdown = true;
 }
 
 void arch_suspend_cpu(unsigned int cpu_id)
diff --git a/hypervisor/arch/arm64/entry.S b/hypervisor/arch/arm64/entry.S
index 3cf9540..cab4810 100644
--- a/hypervisor/arch/arm64/entry.S
+++ b/hypervisor/arch/arm64/entry.S
@@ -110,6 +110,39 @@ el2_entry:
        bl      entry
        b       .
 
+       .globl arch_shutdown_mmu
+arch_shutdown_mmu:
+       /* x0: struct percpu* */
+       mov     x19, x0
+
+       /* Note: no memory accesses must be done after turning MMU off. There
+        * is non-zero probability that cached data can be not syncronized with
+        * system memory. CPU can access data bypassing D-cache when MMU is off.
+        */
+
+       /* hand over control of EL2 back to Linux */
+       add     x1, x19, #PERCPU_LINUX_SAVED_VECTORS
+       ldr     x2, [x1]
+       msr     vbar_el2, x2
+
+       /* disable the hypervisor MMU */
+       mrs     x1, sctlr_el2
+       ldr     x2, =(SCTLR_M_BIT | SCTLR_C_BIT | SCTLR_I_BIT)
+       bic     x1, x1, x2
+       msr     sctlr_el2, x1
+       isb
+
+       msr     mair_el2, xzr
+       msr     ttbr0_el2, xzr
+       msr     tcr_el2, xzr
+       isb
+
+       msr     tpidr_el2, xzr
+
+       /* Call vmreturn(guest_registers) */
+       add     x0, x19, #(PERCPU_STACK_END - 32 * 8)
+       b       vmreturn
+
        .globl enable_mmu_el2
 enable_mmu_el2:
        /*
diff --git a/hypervisor/arch/arm64/include/asm/percpu.h 
b/hypervisor/arch/arm64/include/asm/percpu.h
index d168dd5..49a1d09 100644
--- a/hypervisor/arch/arm64/include/asm/percpu.h
+++ b/hypervisor/arch/arm64/include/asm/percpu.h
@@ -57,6 +57,7 @@ struct per_cpu {
        struct psci_mbox guest_mbox;
 
        unsigned long mpidr;
+       bool shutdown;
 } __attribute__((aligned(PAGE_SIZE)));
 
 static inline struct per_cpu *this_cpu_data(void)
diff --git a/hypervisor/arch/arm64/setup.c b/hypervisor/arch/arm64/setup.c
index 55dda3e..be07395 100644
--- a/hypervisor/arch/arm64/setup.c
+++ b/hypervisor/arch/arm64/setup.c
@@ -87,8 +87,40 @@ int arch_unmap_device(void *vaddr, unsigned long size)
                        PAGING_NON_COHERENT);
 }
 
+/* disable the hypervisor on the current CPU */
+void arch_shutdown_self(struct per_cpu *cpu_data)
+{
+       irqchip_cpu_shutdown(cpu_data);
+
+       /* Free the guest */
+       arm_write_sysreg(HCR_EL2, HCR_RW_BIT);
+       arm_write_sysreg(VTCR_EL2, VTCR_RES1);
+
+       /* Remove stage-2 mappings */
+       arch_cpu_tlb_flush(cpu_data);
+
+       /* TLB flush needs the cell's VMID */
+       isb();
+       arm_write_sysreg(VTTBR_EL2, 0);
+
+       /* we will restore the root cell state with the MMU turned off,
+        * so we need to make sure it has been commited to memory */
+       arch_paging_flush_cpu_caches(guest_regs(cpu_data),
+                                    sizeof(struct registers));
+       dsb(ish);
+
+       /* Return to EL1 */
+       arch_shutdown_mmu(cpu_data);
+}
+
 void arch_cpu_restore(struct per_cpu *cpu_data, int return_code)
 {
-       trace_error(-EINVAL);
-       while (1);
+       struct registers *regs = guest_regs(cpu_data);
+
+       /* Jailhouse initialization failed; return to the caller in EL1 */
+       arm_write_sysreg(ELR_EL2, regs->usr[30]);
+
+       regs->usr[0] = return_code;
+
+       arch_shutdown_self(cpu_data);
 }
diff --git a/hypervisor/arch/arm64/traps.c b/hypervisor/arch/arm64/traps.c
index 45163fd..9c7f486 100644
--- a/hypervisor/arch/arm64/traps.c
+++ b/hypervisor/arch/arm64/traps.c
@@ -196,5 +196,9 @@ struct registers *arch_handle_exit(struct per_cpu *cpu_data,
                panic_stop();
        }
 
+       if (cpu_data->shutdown)
+               /* Won't return here. */
+               arch_shutdown_self(cpu_data);
+
        vmreturn(regs);
 }
-- 
2.8.0.rc3


-- 
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 [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to