VHE: Update cpu code to allow for el0 partition execution
To run a el0 partitions vcpu the following changes are required:
1) HCR_EL2.TGE bit always needs to be set.
2) SPSR needs to be set to EL0t mode.
3) ttbr0_el2 needs to switched to the appropriate table. To do this a
new vcpu field for ttbr0_el2 is added. For normal VM's, ttbr0_el2 is the
same as the hypervisor page tables and for el0 partition's, the
appropriate page table and asid are used. ttbr0_el2 is now loaded on
every exit from el2.
Change-Id: I92a44874d820080a8e9a66dc0b6a628bf94d0b9d
Signed-off-by: Raghu Krishnamurthy <raghu.ncstate@gmail.com>
diff --git a/src/arch/aarch64/hypervisor/cpu.c b/src/arch/aarch64/hypervisor/cpu.c
index eeb9eb1..a75cff3 100644
--- a/src/arch/aarch64/hypervisor/cpu.c
+++ b/src/arch/aarch64/hypervisor/cpu.c
@@ -99,30 +99,45 @@
}
}
- r->hcr_el2 = get_hcr_el2_value(vm_id);
+ r->hcr_el2 = get_hcr_el2_value(vm_id, vcpu->vm->el0_partition);
r->lazy.cnthctl_el2 = cnthctl;
- r->lazy.vttbr_el2 = pa_addr(table) | ((uint64_t)vm_id << 48);
- r->lazy.vmpidr_el2 = vcpu_id;
- /* Mask (disable) interrupts and run in EL1h mode. */
- r->spsr = PSR_D | PSR_A | PSR_I | PSR_F | PSR_PE_MODE_EL1H;
+ if (vcpu->vm->el0_partition) {
+ CHECK(has_vhe_support());
+ /*
+ * AArch64 hafnium only uses 8 bit ASIDs at the moment.
+ * TCR_EL2.AS is set to 0, and per the Arm ARM, the upper 8 bits
+ * are ignored and treated as 0. There is no need to mask the
+ * VMID (used as asid) to only 8 bits.
+ */
+ r->ttbr0_el2 = pa_addr(table) | ((uint64_t)vm_id << 48);
+ r->spsr = PSR_PE_MODE_EL0T;
+ } else {
+ r->ttbr0_el2 = read_msr(ttbr0_el2);
+ r->lazy.vttbr_el2 = pa_addr(table) | ((uint64_t)vm_id << 48);
+ r->lazy.vmpidr_el2 = vcpu_id;
+ /* Mask (disable) interrupts and run in EL1h mode. */
+ r->spsr = PSR_D | PSR_A | PSR_I | PSR_F | PSR_PE_MODE_EL1H;
- r->lazy.mdcr_el2 = get_mdcr_el2_value();
+ r->lazy.mdcr_el2 = get_mdcr_el2_value();
- /*
- * NOTE: It is important that MDSCR_EL1.MDE (bit 15) is set to 0 for
- * secondary VMs as long as Hafnium does not support debug register
- * access for secondary VMs. If adding Hafnium support for secondary VM
- * debug register accesses, then on context switches Hafnium needs to
- * save/restore EL1 debug register state that either might change, or
- * that needs to be protected.
- */
- r->lazy.mdscr_el1 = 0x0U & ~(0x1U << 15);
+ /*
+ * NOTE: It is important that MDSCR_EL1.MDE (bit 15) is set to 0
+ * for secondary VMs as long as Hafnium does not support debug
+ * register access for secondary VMs. If adding Hafnium support
+ * for secondary VM debug register accesses, then on context
+ * switches Hafnium needs to save/restore EL1 debug register
+ * state that either might change, or that needs to be
+ * protected.
+ */
+ r->lazy.mdscr_el1 = 0x0U & ~(0x1U << 15);
- /* Disable cycle counting on initialization. */
- r->lazy.pmccfiltr_el0 = perfmon_get_pmccfiltr_el0_init_value(vm_id);
+ /* Disable cycle counting on initialization. */
+ r->lazy.pmccfiltr_el0 =
+ perfmon_get_pmccfiltr_el0_init_value(vm_id);
- /* Set feature-specific register values. */
- feature_set_traps(vcpu->vm, r);
+ /* Set feature-specific register values. */
+ feature_set_traps(vcpu->vm, r);
+ }
#if SECURE_WORLD == 1
/*
diff --git a/src/arch/aarch64/hypervisor/exceptions.S b/src/arch/aarch64/hypervisor/exceptions.S
index fb57960..2482d92 100644
--- a/src/arch/aarch64/hypervisor/exceptions.S
+++ b/src/arch/aarch64/hypervisor/exceptions.S
@@ -805,6 +805,11 @@
ldr x1, [x0, #VCPU_REGS + 8 * 33]
msr hcr_el2, x1
+ isb
+
+ ldr x1, [x0, #VCPU_REGS + 8 * 34]
+ msr ttbr0_el2, x1
+ isb
/* Restore x0..x3, which we have used as scratch before. */
ldp x2, x3, [x0, #VCPU_REGS + 8 * 2]
diff --git a/src/arch/aarch64/inc/hf/arch/types.h b/src/arch/aarch64/inc/hf/arch/types.h
index a8cdf46..0248522 100644
--- a/src/arch/aarch64/inc/hf/arch/types.h
+++ b/src/arch/aarch64/inc/hf/arch/types.h
@@ -80,6 +80,7 @@
uintreg_t pc;
uintreg_t spsr;
uintreg_t hcr_el2;
+ uintreg_t ttbr0_el2;
/*
* System registers.
diff --git a/src/arch/aarch64/sysregs.c b/src/arch/aarch64/sysregs.c
index 6ca8187..124760d 100644
--- a/src/arch/aarch64/sysregs.c
+++ b/src/arch/aarch64/sysregs.c
@@ -27,7 +27,7 @@
* Returns the value for HCR_EL2 for the particular VM.
* For now, the primary VM has one value and all secondary VMs share a value.
*/
-uintreg_t get_hcr_el2_value(ffa_vm_id_t vm_id)
+uintreg_t get_hcr_el2_value(ffa_vm_id_t vm_id, bool is_el0_partition)
{
uintreg_t hcr_el2_value = 0;
@@ -109,6 +109,9 @@
/* Enable VHE, if enabled by build and if HW supports it. */
if (has_vhe_support()) {
hcr_el2_value |= HCR_EL2_E2H;
+ if (is_el0_partition) {
+ hcr_el2_value |= HCR_EL2_TGE;
+ }
}
return hcr_el2_value;
diff --git a/src/arch/aarch64/sysregs.h b/src/arch/aarch64/sysregs.h
index da8885e..5f7a7c4 100644
--- a/src/arch/aarch64/sysregs.h
+++ b/src/arch/aarch64/sysregs.h
@@ -631,7 +631,7 @@
#define ID_AA64MMFR1_EL1_VH_MASK UINT64_C(0xf)
#define ID_AA64MMFR1_EL1_VH_SUPPORTED UINT64_C(0x1)
-uintreg_t get_hcr_el2_value(ffa_vm_id_t vm_id);
+uintreg_t get_hcr_el2_value(ffa_vm_id_t vm_id, bool is_el0_partition);
uintreg_t get_mdcr_el2_value(void);