[RFC PATCH 2/3] arm64: KVM: trap VM system registers until MMU and caches are ON

Anup Patel anup at brainfault.org
Mon Jan 20 07:00:40 EST 2014


On Fri, Jan 17, 2014 at 8:33 PM, Marc Zyngier <marc.zyngier at arm.com> wrote:
> In order to be able to detect the point where the guest enables
> its MMU and caches, trap all the VM related system registers.
>
> Once we see the guest enabling both the MMU and the caches, we
> can go back to a saner mode of operation, which is to leave these
> registers in complete control of the guest.
>
> Signed-off-by: Marc Zyngier <marc.zyngier at arm.com>
> Reviewed-by: Catalin Marinas <catalin.marinas at arm.com>
> ---
>  arch/arm64/include/asm/kvm_arm.h |  3 ++-
>  arch/arm64/kvm/sys_regs.c        | 58 ++++++++++++++++++++++++++++++++--------
>  2 files changed, 49 insertions(+), 12 deletions(-)
>
> diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h
> index c98ef47..fd0a651 100644
> --- a/arch/arm64/include/asm/kvm_arm.h
> +++ b/arch/arm64/include/asm/kvm_arm.h
> @@ -62,6 +62,7 @@
>   * RW:         64bit by default, can be overriden for 32bit VMs
>   * TAC:                Trap ACTLR
>   * TSC:                Trap SMC
> + * TVM:                Trap VM ops (until M+C set in SCTLR_EL1)
>   * TSW:                Trap cache operations by set/way
>   * TWE:                Trap WFE
>   * TWI:                Trap WFI
> @@ -74,7 +75,7 @@
>   * SWIO:       Turn set/way invalidates into set/way clean+invalidate
>   */
>  #define HCR_GUEST_FLAGS (HCR_TSC | HCR_TSW | HCR_TWE | HCR_TWI | HCR_VM | \
> -                        HCR_BSU_IS | HCR_FB | HCR_TAC | \
> +                        HCR_TVM | HCR_BSU_IS | HCR_FB | HCR_TAC | \
>                          HCR_AMO | HCR_IMO | HCR_FMO | \
>                          HCR_SWIO | HCR_TIDCP | HCR_RW)
>  #define HCR_VIRT_EXCP_MASK (HCR_VA | HCR_VI | HCR_VF)
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index 02e9d09..5e92b9e 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -121,6 +121,42 @@ done:
>  }
>
>  /*
> + * Generic accessor for VM registers. Only called as long as HCR_TVM
> + * is set.
> + */
> +static bool access_vm_reg(struct kvm_vcpu *vcpu,
> +                         const struct sys_reg_params *p,
> +                         const struct sys_reg_desc *r)
> +{
> +       BUG_ON(!p->is_write);
> +
> +       vcpu_sys_reg(vcpu, r->reg) = *vcpu_reg(vcpu, p->Rt);
> +       return true;
> +}
> +
> +/*
> + * SCTLR_EL1 accessor. Only called as long as HCR_TVM is set.  If the
> + * guest enables the MMU, we stop trapping the VM sys_regs and leave
> + * it in complete control of the caches.
> + */
> +static bool access_sctlr_el1(struct kvm_vcpu *vcpu,
> +                            const struct sys_reg_params *p,
> +                            const struct sys_reg_desc *r)
> +{
> +       unsigned long val;
> +
> +       BUG_ON(!p->is_write);
> +
> +       val = *vcpu_reg(vcpu, p->Rt);
> +       vcpu_sys_reg(vcpu, r->reg) = val;
> +
> +       if ((val & (0b101)) == 0b101)   /* MMU+Caches enabled? */
> +               vcpu->arch.hcr_el2 &= ~HCR_TVM;
> +
> +       return true;
> +}
> +
> +/*
>   * We could trap ID_DFR0 and tell the guest we don't support performance
>   * monitoring.  Unfortunately the patch to make the kernel check ID_DFR0 was
>   * NAKed, so it will read the PMCR anyway.
> @@ -185,32 +221,32 @@ static const struct sys_reg_desc sys_reg_descs[] = {
>           NULL, reset_mpidr, MPIDR_EL1 },
>         /* SCTLR_EL1 */
>         { Op0(0b11), Op1(0b000), CRn(0b0001), CRm(0b0000), Op2(0b000),
> -         NULL, reset_val, SCTLR_EL1, 0x00C50078 },
> +         access_sctlr_el1, reset_val, SCTLR_EL1, 0x00C50078 },

This patch in its current form breaks Aarch32 VMs on Foundation v8 Model
because encoding for Aarch64 VM registers we get Op0=0b11 and for Aarch32
VM registers we get Op0=0b00 when trapped.

Either its a Foundation v8 Model bug or we need to add more enteries in
sys_reg_desc[] for Aarch32 VM registers with Op0=0b00.

>         /* CPACR_EL1 */
>         { Op0(0b11), Op1(0b000), CRn(0b0001), CRm(0b0000), Op2(0b010),
>           NULL, reset_val, CPACR_EL1, 0 },
>         /* TTBR0_EL1 */
>         { Op0(0b11), Op1(0b000), CRn(0b0010), CRm(0b0000), Op2(0b000),
> -         NULL, reset_unknown, TTBR0_EL1 },
> +         access_vm_reg, reset_unknown, TTBR0_EL1 },
>         /* TTBR1_EL1 */
>         { Op0(0b11), Op1(0b000), CRn(0b0010), CRm(0b0000), Op2(0b001),
> -         NULL, reset_unknown, TTBR1_EL1 },
> +         access_vm_reg, reset_unknown, TTBR1_EL1 },
>         /* TCR_EL1 */
>         { Op0(0b11), Op1(0b000), CRn(0b0010), CRm(0b0000), Op2(0b010),
> -         NULL, reset_val, TCR_EL1, 0 },
> +         access_vm_reg, reset_val, TCR_EL1, 0 },
>
>         /* AFSR0_EL1 */
>         { Op0(0b11), Op1(0b000), CRn(0b0101), CRm(0b0001), Op2(0b000),
> -         NULL, reset_unknown, AFSR0_EL1 },
> +         access_vm_reg, reset_unknown, AFSR0_EL1 },
>         /* AFSR1_EL1 */
>         { Op0(0b11), Op1(0b000), CRn(0b0101), CRm(0b0001), Op2(0b001),
> -         NULL, reset_unknown, AFSR1_EL1 },
> +         access_vm_reg, reset_unknown, AFSR1_EL1 },
>         /* ESR_EL1 */
>         { Op0(0b11), Op1(0b000), CRn(0b0101), CRm(0b0010), Op2(0b000),
> -         NULL, reset_unknown, ESR_EL1 },
> +         access_vm_reg, reset_unknown, ESR_EL1 },
>         /* FAR_EL1 */
>         { Op0(0b11), Op1(0b000), CRn(0b0110), CRm(0b0000), Op2(0b000),
> -         NULL, reset_unknown, FAR_EL1 },
> +         access_vm_reg, reset_unknown, FAR_EL1 },
>         /* PAR_EL1 */
>         { Op0(0b11), Op1(0b000), CRn(0b0111), CRm(0b0100), Op2(0b000),
>           NULL, reset_unknown, PAR_EL1 },
> @@ -224,17 +260,17 @@ static const struct sys_reg_desc sys_reg_descs[] = {
>
>         /* MAIR_EL1 */
>         { Op0(0b11), Op1(0b000), CRn(0b1010), CRm(0b0010), Op2(0b000),
> -         NULL, reset_unknown, MAIR_EL1 },
> +         access_vm_reg, reset_unknown, MAIR_EL1 },
>         /* AMAIR_EL1 */
>         { Op0(0b11), Op1(0b000), CRn(0b1010), CRm(0b0011), Op2(0b000),
> -         NULL, reset_amair_el1, AMAIR_EL1 },
> +         access_vm_reg, reset_amair_el1, AMAIR_EL1 },
>
>         /* VBAR_EL1 */
>         { Op0(0b11), Op1(0b000), CRn(0b1100), CRm(0b0000), Op2(0b000),
>           NULL, reset_val, VBAR_EL1, 0 },
>         /* CONTEXTIDR_EL1 */
>         { Op0(0b11), Op1(0b000), CRn(0b1101), CRm(0b0000), Op2(0b001),
> -         NULL, reset_val, CONTEXTIDR_EL1, 0 },
> +         access_vm_reg, reset_val, CONTEXTIDR_EL1, 0 },
>         /* TPIDR_EL1 */
>         { Op0(0b11), Op1(0b000), CRn(0b1101), CRm(0b0000), Op2(0b100),
>           NULL, reset_unknown, TPIDR_EL1 },
> --
> 1.8.3.4
>
> _______________________________________________
> kvmarm mailing list
> kvmarm at lists.cs.columbia.edu
> https://lists.cs.columbia.edu/cucslists/listinfo/kvmarm

Regards,
Anup



More information about the linux-arm-kernel mailing list