#include <jailhouse/string.h>
#include <asm/control.h>
#include <asm/irqchip.h>
+#include <asm/processor.h>
#include <asm/sysregs.h>
#include <asm/traps.h>
static void arch_reset_el1(struct registers *regs)
{
+ u32 sctlr;
+
/* Wipe all banked and usr regs */
memset(regs, 0, sizeof(struct registers));
arm_write_banked_reg(SPSR_fiq, 0);
/* Wipe the system registers */
- arm_write_sysreg(SCTLR_EL1, 0);
+ arm_read_sysreg(SCTLR_EL1, sctlr);
+ sctlr = sctlr & ~SCTLR_MASK;
+ arm_write_sysreg(SCTLR_EL1, sctlr);
arm_write_sysreg(ACTLR_EL1, 0);
arm_write_sysreg(CPACR_EL1, 0);
arm_write_sysreg(CONTEXTIDR_EL1, 0);
{
int err;
unsigned long reset_address;
+ struct cell *cell = cpu_data->cell;
struct registers *regs = guest_regs(cpu_data);
err = arch_mmu_cpu_cell_init(cpu_data);
if (err)
printk("MMU setup failed\n");
+ /*
+ * On the first CPU to reach this, write all cell datas to memory so it
+ * can be started with caches disabled.
+ * On all CPUs, invalidate the instruction caches to take into account
+ * the potential new instructions.
+ */
+ arch_cell_caches_flush(cell);
/*
* We come from the IRQ handler, but we won't return there, so the IPI
/* CPU must be stopped */
void arch_park_cpu(unsigned int cpu_id)
{
+ 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;
}
/* CPU must be stopped */
#define SCTLR_AFE_BIT (1 << 29)
#define SCTLR_TE_BIT (1 << 30)
+/* Bits to wipe on cell reset */
+#define SCTLR_MASK (SCTLR_M_BIT | SCTLR_A_BIT | SCTLR_C_BIT \
+ | SCTLR_I_BIT | SCTLR_V_BIT | SCTLR_WXN_BIT \
+ | SCTLR_UWXN_BIT | SCTLR_FI_BIT | SCTLR_EE_BIT \
+ | SCTLR_TRE_BIT | SCTLR_AFE_BIT | SCTLR_TE_BIT)
+
+
#define HCR_TRVM_BIT (1 << 30)
#define HCR_TVM_BIT (1 << 26)
#define HCR_HDC_BIT (1 << 29)
return 0;
}
+
+void arch_cell_caches_flush(struct cell *cell)
+{
+ /* Only the first CPU needs to clean the data caches */
+ spin_lock(&cell->arch.caches_lock);
+ if (cell->arch.needs_flush) {
+ /*
+ * Since there is no way to know which virtual addresses have been used
+ * by the root cell to write the new cell's data, a complete clean has
+ * to be performed.
+ */
+ arch_cpu_dcaches_flush(CACHES_CLEAN_INVALIDATE);
+ cell->arch.needs_flush = false;
+ }
+ spin_unlock(&cell->arch.caches_lock);
+
+ /*
+ * New instructions may have been written, so the I-cache needs to be
+ * invalidated even though the VMID is different.
+ * A complete invalidation is the only way to ensure all virtual aliases
+ * of these memory locations are invalidated, whatever the cache type.
+ */
+ arch_cpu_icache_flush();
+
+ /* ERET will ensure context synchronization */
+}