In order to switch between host and guest, a VHE-enabled kernel
must use different accessors for certain system registers.

This patch uses runtime patching to use the right instruction
when required...

Signed-off-by: Marc Zyngier <marc.zyng...@arm.com>
---
 arch/arm64/include/asm/kvm_asm.h |  40 ++++++--
 arch/arm64/kvm/hyp.S             | 210 ++++++++++++++++++++++++++-------------
 arch/arm64/kvm/vhe-macros.h      |  18 ++++
 3 files changed, 191 insertions(+), 77 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
index 3c5fe68..a932be0 100644
--- a/arch/arm64/include/asm/kvm_asm.h
+++ b/arch/arm64/include/asm/kvm_asm.h
@@ -18,6 +18,7 @@
 #ifndef __ARM_KVM_ASM_H__
 #define __ARM_KVM_ASM_H__
 
+#include <asm/sysreg.h>
 #include <asm/virt.h>
 
 /*
@@ -27,7 +28,7 @@
 #define        MPIDR_EL1       1       /* MultiProcessor Affinity Register */
 #define        CSSELR_EL1      2       /* Cache Size Selection Register */
 #define        SCTLR_EL1       3       /* System Control Register */
-#define        ACTLR_EL1       4       /* Auxiliary Control Register */
+#define        AMAIR_EL1       4       /* Aux Memory Attribute Indirection 
Register */
 #define        CPACR_EL1       5       /* Coprocessor Access Control */
 #define        TTBR0_EL1       6       /* Translation Table Base Register 0 */
 #define        TTBR1_EL1       7       /* Translation Table Base Register 1 */
@@ -39,13 +40,13 @@
 #define        MAIR_EL1        13      /* Memory Attribute Indirection 
Register */
 #define        VBAR_EL1        14      /* Vector Base Address Register */
 #define        CONTEXTIDR_EL1  15      /* Context ID Register */
-#define        TPIDR_EL0       16      /* Thread ID, User R/W */
-#define        TPIDRRO_EL0     17      /* Thread ID, User R/O */
-#define        TPIDR_EL1       18      /* Thread ID, Privileged */
-#define        AMAIR_EL1       19      /* Aux Memory Attribute Indirection 
Register */
-#define        CNTKCTL_EL1     20      /* Timer Control Register (EL1) */
-#define        PAR_EL1         21      /* Physical Address Register */
-#define MDSCR_EL1      22      /* Monitor Debug System Control Register */
+#define        CNTKCTL_EL1     16      /* Timer Control Register (EL1) */
+#define        PAR_EL1         17      /* Physical Address Register */
+#define        MDSCR_EL1       18      /* Monitor Debug System Control 
Register */
+#define        TPIDR_EL0       19      /* Thread ID, User R/W */
+#define        TPIDRRO_EL0     20      /* Thread ID, User R/O */
+#define        TPIDR_EL1       21      /* Thread ID, Privileged */
+#define        ACTLR_EL1       22      /* Auxiliary Control Register */
 #define DBGBCR0_EL1    23      /* Debug Breakpoint Control Registers (0-15) */
 #define DBGBCR15_EL1   38
 #define DBGBVR0_EL1    39      /* Debug Breakpoint Value Registers (0-15) */
@@ -106,6 +107,29 @@
 
 #define NR_COPRO_REGS  (NR_SYS_REGS * 2)
 
+#define sctlr_EL12              sys_reg(3, 5, 1, 0, 0)
+#define cpacr_EL12              sys_reg(3, 5, 1, 0, 2)
+#define ttbr0_EL12              sys_reg(3, 5, 2, 0, 0)
+#define ttbr1_EL12              sys_reg(3, 5, 2, 0, 1)
+#define tcr_EL12                sys_reg(3, 5, 2, 0, 2)
+#define afsr0_EL12              sys_reg(3, 5, 5, 1, 0)
+#define afsr1_EL12              sys_reg(3, 5, 5, 1, 1)
+#define esr_EL12                sys_reg(3, 5, 5, 2, 0)
+#define far_EL12                sys_reg(3, 5, 6, 0, 0)
+#define mair_EL12               sys_reg(3, 5, 10, 2, 0)
+#define amair_EL12              sys_reg(3, 5, 10, 3, 0)
+#define vbar_EL12               sys_reg(3, 5, 12, 0, 0)
+#define contextidr_EL12         sys_reg(3, 5, 13, 0, 1)
+#define cntkctl_EL12            sys_reg(3, 5, 14, 1, 0)
+#define cntp_tval_EL02          sys_reg(3, 5, 14, 2, 0)
+#define cntp_ctl_EL02           sys_reg(3, 5, 14, 2, 1)
+#define cntp_cval_EL02          sys_reg(3, 5, 14, 2, 2)
+#define cntv_tval_EL02          sys_reg(3, 5, 14, 3, 0)
+#define cntv_ctl_EL02           sys_reg(3, 5, 14, 3, 1)
+#define cntv_cval_EL02          sys_reg(3, 5, 14, 3, 2)
+#define spsr_EL12               sys_reg(3, 5, 4, 0, 0)
+#define elr_EL12                sys_reg(3, 5, 4, 0, 1)
+
 #define ARM_EXCEPTION_IRQ        0
 #define ARM_EXCEPTION_TRAP       1
 
diff --git a/arch/arm64/kvm/hyp.S b/arch/arm64/kvm/hyp.S
index ad5821b..b61591b 100644
--- a/arch/arm64/kvm/hyp.S
+++ b/arch/arm64/kvm/hyp.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012,2013 - ARM Ltd
+ * Copyright (C) 2012-2015 - ARM Ltd
  * Author: Marc Zyngier <marc.zyng...@arm.com>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -67,40 +67,52 @@
        stp     x29, lr, [x3, #80]
 
        mrs     x19, sp_el0
-       mrs     x20, elr_el2            // pc before entering el2
-       mrs     x21, spsr_el2           // pstate before entering el2
+       str     x19, [x3, #96]
+.endm
 
-       stp     x19, x20, [x3, #96]
-       str     x21, [x3, #112]
+.macro save_el1_state
+       mrs_hyp(x20, ELR)               // pc before entering el2
+       mrs_hyp(x21, SPSR)              // pstate before entering el2
 
        mrs     x22, sp_el1
-       mrs     x23, elr_el1
-       mrs     x24, spsr_el1
+
+       mrs_el1(x23, elr)
+       mrs_el1(x24, spsr)
+
+       add     x3, x2, #CPU_XREG_OFFSET(31)    // SP_EL0
+       stp     x20, x21, [x3, #8]      // HACK: Store to the regs after SP_EL0
 
        str     x22, [x2, #CPU_GP_REG_OFFSET(CPU_SP_EL1)]
        str     x23, [x2, #CPU_GP_REG_OFFSET(CPU_ELR_EL1)]
        str     x24, [x2, #CPU_SPSR_OFFSET(KVM_SPSR_EL1)]
 .endm
 
-.macro restore_common_regs
+.macro restore_el1_state
        // x2: base address for cpu context
        // x3: tmp register
 
+       add     x3, x2, #CPU_XREG_OFFSET(31)    // SP_EL0
+       ldp     x20, x21, [x3, #8] // Same hack again, get guest PC and pstate
+
        ldr     x22, [x2, #CPU_GP_REG_OFFSET(CPU_SP_EL1)]
        ldr     x23, [x2, #CPU_GP_REG_OFFSET(CPU_ELR_EL1)]
        ldr     x24, [x2, #CPU_SPSR_OFFSET(KVM_SPSR_EL1)]
 
+       msr_hyp(ELR, x20)               // pc on return from el2
+       msr_hyp(SPSR, x21)              // pstate on return from el2
+
        msr     sp_el1, x22
-       msr     elr_el1, x23
-       msr     spsr_el1, x24
 
-       add     x3, x2, #CPU_XREG_OFFSET(31)    // SP_EL0
-       ldp     x19, x20, [x3]
-       ldr     x21, [x3, #16]
+       msr_el1(elr, x23)
+       msr_el1(spsr, x24)
+.endm
 
+.macro restore_common_regs
+       // x2: base address for cpu context
+       // x3: tmp register
+
+       ldr     x19, [x2, #CPU_XREG_OFFSET(31)] // SP_EL0
        msr     sp_el0, x19
-       msr     elr_el2, x20            // pc on return from el2
-       msr     spsr_el2, x21           // pstate on return from el2
 
        add     x3, x2, #CPU_XREG_OFFSET(19)
        ldp     x19, x20, [x3]
@@ -113,9 +125,15 @@
 
 .macro save_host_regs
        save_common_regs
+ifnvhe nop,                                    "b      skip_el1_save"
+       save_el1_state
+skip_el1_save:
 .endm
 
 .macro restore_host_regs
+ifnvhe nop,                                    "b      skip_el1_restore"
+       restore_el1_state
+skip_el1_restore:
        restore_common_regs
 .endm
 
@@ -159,6 +177,7 @@
        stp     x6, x7, [x3, #16]
 
        save_common_regs
+       save_el1_state
 .endm
 
 .macro restore_guest_regs
@@ -184,6 +203,7 @@
        ldr     x18, [x3, #144]
 
        // x19-x29, lr, sp*, elr*, spsr*
+       restore_el1_state
        restore_common_regs
 
        // Last bits of the 64bit state
@@ -203,6 +223,38 @@
  * In other words, don't touch any of these unless you know what
  * you are doing.
  */
+
+.macro save_shared_sysregs
+       // x2: base address for cpu context
+       // x3: tmp register
+
+       add     x3, x2, #CPU_SYSREG_OFFSET(TPIDR_EL0)
+
+       mrs     x4, tpidr_el0
+       mrs     x5, tpidrro_el0
+       mrs     x6, tpidr_el1
+       mrs     x7, actlr_el1
+
+       stp     x4, x5, [x3]
+       stp     x6, x7, [x3, #16]
+.endm
+
+.macro restore_shared_sysregs
+       // x2: base address for cpu context
+       // x3: tmp register
+
+       add     x3, x2, #CPU_SYSREG_OFFSET(TPIDR_EL0)
+
+       ldp     x4, x5, [x3]
+       ldp     x6, x7, [x3, #16]
+
+       msr     tpidr_el0,      x4
+       msr     tpidrro_el0,    x5
+       msr     tpidr_el1,      x6
+       msr     actlr_el1,      x7
+.endm
+
+
 .macro save_sysregs
        // x2: base address for cpu context
        // x3: tmp register
@@ -211,26 +263,27 @@
 
        mrs     x4,     vmpidr_el2
        mrs     x5,     csselr_el1
-       mrs     x6,     sctlr_el1
-       mrs     x7,     actlr_el1
-       mrs     x8,     cpacr_el1
-       mrs     x9,     ttbr0_el1
-       mrs     x10,    ttbr1_el1
-       mrs     x11,    tcr_el1
-       mrs     x12,    esr_el1
-       mrs     x13,    afsr0_el1
-       mrs     x14,    afsr1_el1
-       mrs     x15,    far_el1
-       mrs     x16,    mair_el1
-       mrs     x17,    vbar_el1
-       mrs     x18,    contextidr_el1
-       mrs     x19,    tpidr_el0
-       mrs     x20,    tpidrro_el0
-       mrs     x21,    tpidr_el1
-       mrs     x22,    amair_el1
-       mrs     x23,    cntkctl_el1
-       mrs     x24,    par_el1
-       mrs     x25,    mdscr_el1
+       mrs_el1(x6,     sctlr)
+       mrs_el1(x7,     amair)
+       mrs_el1(x8,     cpacr)
+       mrs_el1(x9,     ttbr0)
+       mrs_el1(x10,    ttbr1)
+       mrs_el1(x11,    tcr)
+       mrs_el1(x12,    esr)
+       mrs_el1(x13,    afsr0)
+       mrs_el1(x14,    afsr1)
+       mrs_el1(x15,    far)
+       mrs_el1(x16,    mair)
+       mrs_el1(x17,    vbar)
+       mrs_el1(x18,    contextidr)
+       mrs_el1(x19,    cntkctl)
+       mrs     x20,    par_el1
+       mrs     x21,    mdscr_el1
+
+       mrs     x22,    tpidr_el0
+       mrs     x23,    tpidrro_el0
+       mrs     x24,    tpidr_el1
+       mrs     x25,    actlr_el1
 
        stp     x4, x5, [x3]
        stp     x6, x7, [x3, #16]
@@ -460,26 +513,27 @@
 
        msr     vmpidr_el2,     x4
        msr     csselr_el1,     x5
-       msr     sctlr_el1,      x6
-       msr     actlr_el1,      x7
-       msr     cpacr_el1,      x8
-       msr     ttbr0_el1,      x9
-       msr     ttbr1_el1,      x10
-       msr     tcr_el1,        x11
-       msr     esr_el1,        x12
-       msr     afsr0_el1,      x13
-       msr     afsr1_el1,      x14
-       msr     far_el1,        x15
-       msr     mair_el1,       x16
-       msr     vbar_el1,       x17
-       msr     contextidr_el1, x18
-       msr     tpidr_el0,      x19
-       msr     tpidrro_el0,    x20
-       msr     tpidr_el1,      x21
-       msr     amair_el1,      x22
-       msr     cntkctl_el1,    x23
-       msr     par_el1,        x24
-       msr     mdscr_el1,      x25
+       msr_el1(sctlr,          x6)
+       msr_el1(amair,          x7)
+       msr_el1(cpacr,          x8)
+       msr_el1(ttbr0,          x9)
+       msr_el1(ttbr1,          x10)
+       msr_el1(tcr,            x11)
+       msr_el1(esr,            x12)
+       msr_el1(afsr0,          x13)
+       msr_el1(afsr1,          x14)
+       msr_el1(far,            x15)
+       msr_el1(mair,           x16)
+       msr_el1(vbar,           x17)
+       msr_el1(contextidr,     x18)
+       msr_el1(cntkctl,        x19)
+       msr     par_el1,        x20
+       msr     mdscr_el1,      x21
+
+       msr     tpidr_el0,      x22
+       msr     tpidrro_el0,    x23
+       msr     tpidr_el1,      x24
+       msr     actlr_el1,      x25
 .endm
 
 .macro restore_debug
@@ -779,8 +833,11 @@
 .macro activate_traps
        ldr     x2, [x0, #VCPU_HCR_EL2]
        msr     hcr_el2, x2
-       mov     x2, #CPTR_EL2_TTA
-       msr     cptr_el2, x2
+       adr     x3, __kvm_hyp_vector
+ifnvhe nop,                                    "msr    vbar_el1, x3"
+ifnvhe nop,                                    "mrs    x2, cpacr_el1"
+ifnvhe _S_(ldr x2, =(CPTR_EL2_TTA)),           "orr x2, x2, #(1 << 28)"
+ifnvhe "msr    cptr_el2, x2",                  "msr    cpacr_el1, x2"
 
        mov     x2, #(1 << 15)  // Trap CP15 Cr=15
        msr     hstr_el2, x2
@@ -803,12 +860,20 @@
 ifnvhe _S_(mov x2, #HCR_RW),                   _S_(mov x2, #HCR_RW|HCR_TGE)
 ifnvhe         nop,                                    _S_(orr x2, x2, 
#HCR_E2H)
        msr     hcr_el2, x2
-       msr     cptr_el2, xzr
+
+ifnvhe nop,                                    "mrs    x2, cpacr_el1"
+ifnvhe nop,                                    "movn   x3, #(1 << 12), lsl #16"
+ifnvhe nop,                                    "and    x2, x2, x3"
+ifnvhe "msr    cptr_el2, xzr",                 "msr    cpacr_el1, x2"
        msr     hstr_el2, xzr
 
        mrs     x2, mdcr_el2
        and     x2, x2, #MDCR_EL2_HPMN_MASK
        msr     mdcr_el2, x2
+
+       adrp    x2, vectors
+       add     x2, x2, #:lo12:vectors
+ifnvhe nop,                                    "msr    vbar_el1, x2"
 .endm
 
 .macro activate_vm
@@ -853,15 +918,15 @@ ifnvhe    nop,                                    _S_(orr 
x2, x2, #HCR_E2H)
        ldr     w3, [x2, #KVM_TIMER_ENABLED]
        cbz     w3, 1f
 
-       mrs     x3, cntv_ctl_el0
+       mrs_el0(x3, cntv_ctl)
        and     x3, x3, #3
        str     w3, [x0, #VCPU_TIMER_CNTV_CTL]
        bic     x3, x3, #1              // Clear Enable
-       msr     cntv_ctl_el0, x3
+       msr_el0(cntv_ctl, x3)
 
        isb
 
-       mrs     x3, cntv_cval_el0
+       mrs_el0(x3, cntv_cval)
        str     x3, [x0, #VCPU_TIMER_CNTV_CVAL]
 
 1:
@@ -871,7 +936,7 @@ ifnvhe      nop,                                    _S_(orr 
x2, x2, #HCR_E2H)
        msr     cnthctl_el2, x2
 
        // Clear cntvoff for the host
-       msr     cntvoff_el2, xzr
+ifnvhe "msr    cntvoff_el2, xzr",              nop
 .endm
 
 .macro restore_timer_state
@@ -891,12 +956,12 @@ ifnvhe    nop,                                    _S_(orr 
x2, x2, #HCR_E2H)
        ldr     x3, [x2, #KVM_TIMER_CNTVOFF]
        msr     cntvoff_el2, x3
        ldr     x2, [x0, #VCPU_TIMER_CNTV_CVAL]
-       msr     cntv_cval_el0, x2
+       msr_el0(cntv_cval, x2)
        isb
 
        ldr     w2, [x0, #VCPU_TIMER_CNTV_CTL]
        and     x2, x2, #3
-       msr     cntv_ctl_el0, x2
+       msr_el0(cntv_ctl, x2)
 1:
 .endm
 
@@ -945,8 +1010,10 @@ ENTRY(__kvm_vcpu_run)
 
        save_host_regs
        bl __save_fpsimd
-       bl __save_sysregs
-
+ifnvhe "bl     __save_sysregs",                nop
+ifnvhe "b      1f",                            nop
+       save_shared_sysregs
+1:
        compute_debug_state 1f
        bl      __save_debug
 1:
@@ -997,7 +1064,10 @@ __kvm_vcpu_return:
        ldr     x2, [x0, #VCPU_HOST_CONTEXT]
        kern_hyp_va x2
 
-       bl __restore_sysregs
+ifnvhe "bl     __restore_sysregs",             nop
+ifnvhe "b      1f",                            nop
+       restore_shared_sysregs
+1:
        bl __restore_fpsimd
 
        skip_debug_state x3, 1f
@@ -1104,6 +1174,8 @@ __kvm_hyp_panic:
        mrs     x6, par_el1
        mrs     x7, tpidr_el2
 
+ifnvhe nop,                                    "b      panic"
+
        mov     lr, #(PSR_F_BIT | PSR_I_BIT | PSR_A_BIT | PSR_D_BIT |\
                      PSR_MODE_EL1h)
        msr     spsr_el2, lr
@@ -1248,7 +1320,7 @@ el1_trap:
         * As such, we can use the EL1 translation regime, and don't have
         * to distinguish between EL0 and EL1 access.
         */
-       mrs     x2, far_el2
+ifnvhe "mrs    x2, far_el2",                   "mrs    x2, far_el1"
        at      s1e1r, x2
        isb
 
@@ -1262,7 +1334,7 @@ el1_trap:
        b       2f
 
 1:     mrs     x3, hpfar_el2
-       mrs     x2, far_el2
+ifnvhe "mrs    x2, far_el2",                   "mrs    x2, far_el1"
 
 2:     mrs     x0, tpidr_el2
        str     w1, [x0, #VCPU_ESR_EL2]
diff --git a/arch/arm64/kvm/vhe-macros.h b/arch/arm64/kvm/vhe-macros.h
index da7f9da..1e94235 100644
--- a/arch/arm64/kvm/vhe-macros.h
+++ b/arch/arm64/kvm/vhe-macros.h
@@ -31,6 +31,24 @@
        alternative_insn        "\nonvhe", "\vhe", ARM64_HAS_VIRT_HOST_EXTN
 .endm
 
+#define mrs_el0(reg, sysreg)   \
+       ifnvhe  _S_(mrs reg, sysreg##_EL0), _S_(mrs_s reg, sysreg##_EL02)
+
+#define msr_el0(sysreg, reg)   \
+       ifnvhe  _S_(msr sysreg##_EL0, reg), _S_(msr_s sysreg##_EL02, reg)
+
+#define mrs_el1(reg, sysreg)   \
+       ifnvhe  _S_(mrs reg, sysreg##_EL1), _S_(mrs_s reg, sysreg##_EL12)
+
+#define msr_el1(sysreg, reg)   \
+       ifnvhe  _S_(msr sysreg##_EL1, reg), _S_(msr_s sysreg##_EL12, reg)
+
+#define mrs_hyp(reg, sysreg)   \
+       ifnvhe  _S_(mrs reg, sysreg##_EL2), _S_(mrs reg, sysreg##_EL1)
+
+#define msr_hyp(sysreg, reg)   \
+       ifnvhe  _S_(msr sysreg##_EL2, reg), _S_(msr sysreg##_EL1, reg)
+
 #endif
 
 #endif /*__ARM64_VHE_MACROS_H__  */
-- 
2.1.4

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to