From: Antonios Motakis <[email protected]> This patch mostly implements the functionality needed to create and control new cells. The functionality is very similar to the one from AArch32, and there is potential to unify some code in the future between the architectures.
Signed-off-by: Antonios Motakis <[email protected]> --- hypervisor/arch/arm64/control.c | 147 +++++++++++++++++++++++++++------ hypervisor/include/jailhouse/control.h | 6 ++ 2 files changed, 126 insertions(+), 27 deletions(-) diff --git a/hypervisor/arch/arm64/control.c b/hypervisor/arch/arm64/control.c index 0e1c780..fac01cf 100644 --- a/hypervisor/arch/arm64/control.c +++ b/hypervisor/arch/arm64/control.c @@ -72,50 +72,97 @@ static void arch_reset_el1(struct registers *regs) void arch_reset_self(struct per_cpu *cpu_data) { int err = 0; - unsigned long reset_address; + unsigned long reset_address = 0; struct cell *cell = cpu_data->cell; struct registers *regs = guest_regs(cpu_data); + bool is_shutdown = cpu_data->shutdown; - if (cell != &root_cell) { - trace_error(-EINVAL); - panic_stop(); - } + if (!is_shutdown) + err = arch_mmu_cpu_cell_init(cpu_data); + if (err) + printk("MMU setup failed\n"); /* * Note: D-cache cleaning and I-cache invalidation is done on driver * level after image is loaded. */ - err = irqchip_cpu_reset(cpu_data); - if (err) - printk("IRQ setup failed\n"); + /* + * We come from the IRQ handler, but we won't return there, so the IPI + * is deactivated here. + */ + irqchip_eoi_irq(SGI_CPU_OFF, true); + + if (is_shutdown) { + if (cell != &root_cell) { + irqchip_cpu_shutdown(cpu_data); + + smc(PSCI_CPU_OFF, 0, 0, 0); + panic_printk("FATAL: PSCI_CPU_OFF failed\n"); + panic_stop(); + } + /* arch_shutdown_self resets the GIC on all remaining CPUs. */ + } else { + err = irqchip_cpu_reset(cpu_data); + if (err) + printk("IRQ setup failed\n"); + } - /* Wait for the driver to call cpu_up */ - reset_address = psci_emulate_spin(cpu_data); + /* All but the first CPU at reset are waiting for a PSCI resume */ + if (cpu_data->cpu_id != first_cpu(cell->cpu_set)) + reset_address = psci_emulate_spin(cpu_data); /* Restore an empty context */ arch_reset_el1(regs); arm_write_sysreg(ELR_EL2, reset_address); + if (is_shutdown) + /* Won't return here. */ + arch_shutdown_self(cpu_data); + vmreturn(regs); } int arch_cell_create(struct cell *cell) { - return trace_error(-EINVAL); + int err; + + err = arch_mmu_cell_init(cell); + if (err) + return err; + + err = irqchip_cell_init(cell); + if (err) { + arch_mmu_cell_destroy(cell); + return err; + } + irqchip_root_cell_shrink(cell); + + return 0; } void arch_flush_cell_vcpu_caches(struct cell *cell) { - /* AARCH64_TODO */ - trace_error(-EINVAL); + unsigned int cpu; + + for_each_cpu(cpu, cell->cpu_set) + if (cpu == this_cpu_id()) + arch_cpu_tlb_flush(per_cpu(cpu)); + else + per_cpu(cpu)->flush_vcpu_caches = true; } void arch_cell_destroy(struct cell *cell) { - trace_error(-EINVAL); - while (1); + unsigned int cpu; + + for_each_cpu(cpu, cell->cpu_set) + arch_reset_cpu(cpu); + + irqchip_cell_exit(cell); + + arch_mmu_cell_destroy(cell); } void arch_config_commit(struct cell *cell_added_removed) @@ -134,38 +181,73 @@ void arch_shutdown(void) void arch_suspend_cpu(unsigned int cpu_id) { - trace_error(-EINVAL); - while (1); + /* TODO: the assumption that cpu_id == gic interface number + * should be eliminated from both the ARMv8 and ARMv7 ports */ + struct sgi sgi; + + if (psci_cpu_stopped(cpu_id)) + return; + + sgi.routing_mode = 0; + sgi.aff1 = 0; + sgi.aff2 = 0; + sgi.aff3 = 0; + sgi.targets = 1 << cpu_id; + sgi.id = SGI_CPU_OFF; + + irqchip_send_sgi(&sgi); + + psci_wait_cpu_stopped(cpu_id); } void arch_resume_cpu(unsigned int cpu_id) { - trace_error(-EINVAL); - while (1); + /* + * Simply get out of the spin loop by returning to handle_sgi + * If the CPU is being reset, it already has left the PSCI idle loop. + */ + if (psci_cpu_stopped(cpu_id)) + psci_resume(cpu_id); } void arch_reset_cpu(unsigned int cpu_id) { - trace_error(-EINVAL); - while (1); + unsigned long cpu_data = (unsigned long)per_cpu(cpu_id); + + if (psci_cpu_on(cpu_id, (unsigned long)arch_reset_self, cpu_data)) + printk("ERROR: unable to reset CPU%d (was running)\n", cpu_id); } void arch_park_cpu(unsigned int cpu_id) { - trace_error(-EINVAL); - while (1); + struct per_cpu *cpu_data = per_cpu(cpu_id); + + /* + * Reset always follows park_cpu, so we just need to make sure that the + * CPU is suspended + */ + if (psci_wait_cpu_stopped(cpu_id) != 0) + printk("ERROR: CPU%d is supposed to be stopped\n", cpu_id); + else + cpu_data->cell->arch.needs_flush = true; } void arch_shutdown_cpu(unsigned int cpu_id) { - trace_error(-EINVAL); - while (1); + struct per_cpu *cpu_data = per_cpu(cpu_id); + + cpu_data->shutdown = true; + + if (psci_wait_cpu_stopped(cpu_id)) + printk("FATAL: unable to stop CPU%d\n", cpu_id); + + arch_reset_cpu(cpu_id); } void __attribute__((noreturn)) arch_panic_stop(void) { - trace_error(-EINVAL); - while (1); + psci_cpu_off(this_cpu_data()); + __builtin_unreachable(); } void arch_panic_park(void) @@ -174,6 +256,14 @@ void arch_panic_park(void) while (1); } +static void arch_suspend_self(struct per_cpu *cpu_data) +{ + psci_suspend(cpu_data); + + if (cpu_data->flush_vcpu_caches) + arch_cpu_tlb_flush(cpu_data); +} + void arch_handle_sgi(struct per_cpu *cpu_data, u32 irqn) { cpu_data->stats[JAILHOUSE_CPU_STAT_VMEXITS_MANAGEMENT]++; @@ -182,6 +272,9 @@ void arch_handle_sgi(struct per_cpu *cpu_data, u32 irqn) case SGI_INJECT: irqchip_inject_pending(cpu_data); break; + case SGI_CPU_OFF: + arch_suspend_self(cpu_data); + break; default: printk("WARN: unknown SGI received %d\n", irqn); } diff --git a/hypervisor/include/jailhouse/control.h b/hypervisor/include/jailhouse/control.h index b83553f..78129f1 100644 --- a/hypervisor/include/jailhouse/control.h +++ b/hypervisor/include/jailhouse/control.h @@ -64,6 +64,12 @@ unsigned int next_cpu(unsigned int cpu, struct cpu_set *cpu_set, ) /** + * Fetch the first CPU from a given set + * @param set Return the first from this CPU set + */ +#define first_cpu(set) next_cpu(-1, (set), -1) + +/** * Loop-generating macro for iterating over all registered cells. * @param cell Iteration variable holding the reference to the current * cell (struct cell *). -- 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.
