Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932182AbbGIU7A (ORCPT ); Thu, 9 Jul 2015 16:59:00 -0400 Received: from mailout3.w2.samsung.com ([211.189.100.13]:13247 "EHLO usmailout3.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753665AbbGIU6u (ORCPT ); Thu, 9 Jul 2015 16:58:50 -0400 X-AuditID: cbfec37a-f79c96d000005f02-97-559ee0880c18 Message-id: <559EE081.7060706@samsung.com> Date: Thu, 09 Jul 2015 13:58:41 -0700 From: Mario Smarduch User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:17.0) Gecko/20130804 Thunderbird/17.0.8 MIME-version: 1.0 To: Marc Zyngier Cc: Catalin Marinas , Will Deacon , Christoffer Dall , "kvmarm@lists.cs.columbia.edu" , "linux-kernel@vger.kernel.org" , "linux-arm-kernel@lists.infradead.org" , "kvm@vger.kernel.org" Subject: Re: [PATCH 09/13] arm64: KVM: VHE: Add alternatives for VHE-enabled world-switch References: <1436372356-30410-1-git-send-email-marc.zyngier@arm.com> <1436372356-30410-10-git-send-email-marc.zyngier@arm.com> <559DCE90.5030209@samsung.com> <559E2B7D.7030807@arm.com> In-reply-to: <559E2B7D.7030807@arm.com> Content-type: text/plain; charset=windows-1252 Content-transfer-encoding: 7bit X-Originating-IP: [105.145.24.65] X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFmpmkeLIzCtJLcpLzFFi42I5/e+wr27Hg3mhBu+uG1q8X9bDaPHi9T9G izlTCy0+njrObrHp8TVWi8u75rBZ/L3zj83i5ccTLA4cHmvmrWH0uHNtD5vH+U1rmD02L6n3 +LxJLoA1issmJTUnsyy1SN8ugSvj9MR9LAULaiuWLrjB1MDYGNDFyMkhIWAi8XXGSUYIW0zi wr31bCC2kMAyRon5MzS7GLmA7CYmiYm71jFCOBsZJf5tuQ5WxSugJbH12nd2EJtFQFXi+raX TCA2m4CuxP57G8HiogIREn9O72OFqBeU+DH5HguILSKgLvG0/xk7yFBmgTZmidP7WsDOEBaI llj9YxMTxLY9jBIHu1+ATeIE6pi+4BLQJA6gDj2J+xe1QMLMAvISm9e8ZYY4W1Vi283njCAl EgKKEvM+ME1gFJ6FZPUshOZZSJoXMDKvYhQrLU4uKE5KT60w1CtOzC0uzUvXS87P3cQIiZqq HYx3vtocYhTgYFTi4W3cOTdUiDWxrLgy9xCjBAezkghv6Z15oUK8KYmVValF+fFFpTmpxYcY pTlYlMR5F0jIhQoJpCeWpGanphakFsFkmTg4pRoYV3SsM+6oD3713XnReubyDzsYr1+//iDp b9Jb045jpzk8w6bMXKzDbnX4en7FVPOkB52F9vsTjjkGl13mav+pUeG89UQBB/P304pMh0+/ 23kzOlJUbUZUv8KBzeXzi3Mex7uL7IxK90tcnrpHvMCUq2LRDitXToOPRWe9ZB/N+yfDLWBu 8ZFXiaU4I9FQi7moOBEAiW9pfZYCAAA= Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 15810 Lines: 472 On 07/09/2015 01:06 AM, Marc Zyngier wrote: > Hi Mario, > > On 09/07/15 02:29, Mario Smarduch wrote: >> On 07/08/2015 09:19 AM, Marc Zyngier wrote: >>> 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 >>> --- >>> 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(-) >>> >> [....] >>> * Author: Marc Zyngier >>> * >>> * 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] >> >> Hi Marc, >> >> trying to make a little sense out of this :) > > Don't even try, it hurts... ;-) > >> In the case of VHE kernel the two 'mrs_hyp()' and 'mrs_el1()' >> calls would be accessing same registers - namely EL1 variants? >> For non VHE EL2, EL1? >> >> The mrs_s and sysreg_EL12 are new, not sure what these mean. > > mrs_s and msr_s are just macros to that deal with system registers that > the assembler doesn't know about (yet). They have been in (moderate) use > for about a year, and have been introduced with the GICv3 support. > > See arch/arm64/include/asm/sysreg.h for the gory details. > > Now, on to sysreg_EL12: The main idea with VHE is that anything that > used to run at EL1 (the kernel) can now run unmodified at EL2, and that > it is the EL2 software that has to change to deal with it. > > So when the kernel uses VHE and runs at EL2, an access to sysreg_EL1 > really accesses sysreg_EL2, transparently. This is what makes it > possible to run the kernel at EL2 without any change. > > But when the KVM world switch wants to access a guest register, it > cannot use sysreg_EL1 anymore (that would hit on the EL2 register > because of the above rule). For this, it must use sysreg_EL12 which > effectively means "access the EL1 register from EL2". > > As a consequence, we have the following rules: > - non-VHE: msr_el1 uses EL1, msr_hyp uses EL2 > - VHE: msr_el1 uses EL12, msr_hyp uses EL1 > > Does this help? Yep it sure does, msr/mrs_hyp() and 12 naming had me confused. Thanks! > > M. > >> - Mario >> >>> +.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__ */ >>> >> > > -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/