From patchwork Thu Dec 7 17:06:20 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christoffer Dall X-Patchwork-Id: 10100215 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id D9D7660360 for ; Thu, 7 Dec 2017 17:08:09 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C3E03284B5 for ; Thu, 7 Dec 2017 17:08:09 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id B8C50284CE; Thu, 7 Dec 2017 17:08:09 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id F19DD284F5 for ; Thu, 7 Dec 2017 17:08:08 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932180AbdLGRIH (ORCPT ); Thu, 7 Dec 2017 12:08:07 -0500 Received: from mail-wm0-f66.google.com ([74.125.82.66]:46964 "EHLO mail-wm0-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932181AbdLGRHX (ORCPT ); Thu, 7 Dec 2017 12:07:23 -0500 Received: by mail-wm0-f66.google.com with SMTP id r78so14371980wme.5 for ; Thu, 07 Dec 2017 09:07:22 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=DcxgfkQZZDbgYaBe2KHjp3nXjvyiPIydGz4ZRgB836w=; b=csU3qy2KbwfwvpsIee7L600+V/s39Xfj8TXpZmNTudqW5XZyEGV6mkaIAFJXOkqoeg Xx9/enb0ODSIVQw4B7wP508X+ycZRaKdLwopi8JeD6ddjQP+GilkJNcWhjplnAveNQix M015gcIfCo4cedp2CAfilke32oLxN8u4yCJdE= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=DcxgfkQZZDbgYaBe2KHjp3nXjvyiPIydGz4ZRgB836w=; b=C77BZLMaMX0yUkKxLFYYIBKKtcxicfAYR84mYRq34aNmNSqQEE42LiUZ3JyPYbh/nl dZLEB2JHLTtXlnhP6vGSl8qwphwm3eoZnjF01IwLhPYgmJDvYvTnRiBEd5fK6u52U0Dy j1Dwu22yechR3UDKWKUPH3gtEi9rZqwE5CZwGVv3NJyKNY75HZUcL6Ukj/0MgZjkLh1m 8CkB66Iv9W/ZA2toiafCnwZ1WS5ZjMHLx+1jfaX9q+7ATWuDDCMAGSWqmR3iZnAprRPo 6hguonzRvLZ0Fa9iCKT6JnDy+yONFo+u4nPefI3bhRNnfnvTSQvQW7YAPoL/iANFXLbE 9Jpg== X-Gm-Message-State: AJaThX7TZQK7fXr9vMOeIV5dFKMKpcgFFyXEVs/uMeFKQwJV8UPt+G0s 9pYAqni5xBjbnx7U8wpvhv4lBQ== X-Google-Smtp-Source: AGs4zMaF5W8IyWWNaj8ydjUfrWfX9QGxrYvjpnyJwZVvpI8nZCfENp6aG1nFc5H7uHaEjVIDcknqoA== X-Received: by 10.80.183.38 with SMTP id g35mr44812545ede.231.1512666441842; Thu, 07 Dec 2017 09:07:21 -0800 (PST) Received: from localhost.localdomain (x50d2404e.cust.hiper.dk. [80.210.64.78]) by smtp.gmail.com with ESMTPSA id a16sm2868270edd.19.2017.12.07.09.07.20 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 07 Dec 2017 09:07:20 -0800 (PST) From: Christoffer Dall To: kvmarm@lists.cs.columbia.edu, linux-arm-kernel@lists.infradead.org Cc: kvm@vger.kernel.org, Marc Zyngier , Shih-Wei Li , Andrew Jones , Christoffer Dall Subject: [PATCH v2 26/36] KVM: arm64: Defer saving/restoring system registers to vcpu load/put on VHE Date: Thu, 7 Dec 2017 18:06:20 +0100 Message-Id: <20171207170630.592-27-christoffer.dall@linaro.org> X-Mailer: git-send-email 2.14.2 In-Reply-To: <20171207170630.592-1-christoffer.dall@linaro.org> References: <20171207170630.592-1-christoffer.dall@linaro.org> Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Some system registers do not affect the host kernel's execution and can therefore be loaded when we are about to run a VCPU and we don't have to restore the host state to the hardware before the time when we are actually about to return to userspace or schedule out the VCPU thread. The EL1 system registers and the userspace state registers, which only affect EL0 execution, do not affect the host kernel's execution. The 32-bit system registers are not used by a VHE host kernel and therefore don't need to be saved/restored on every entry/exit to/from the guest, but can be deferred to vcpu_load and vcpu_put, respectively. We have already prepared the trap handling code which accesses any of these registers to directly access the registers on the physical CPU or to sync the registers when needed. Signed-off-by: Christoffer Dall --- arch/arm64/kvm/hyp/switch.c | 6 ------ arch/arm64/kvm/hyp/sysreg-sr.c | 46 ++++++++++++++++++++++++++++++++++-------- 2 files changed, 38 insertions(+), 14 deletions(-) diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c index c3e1a9c65bc1..2ac8af354de0 100644 --- a/arch/arm64/kvm/hyp/switch.c +++ b/arch/arm64/kvm/hyp/switch.c @@ -359,11 +359,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu) __vgic_restore_state(vcpu); - /* - * We must restore the 32-bit state before the sysregs, thanks - * to erratum #852523 (Cortex-A57) or #853709 (Cortex-A72). - */ - __sysreg32_restore_state(vcpu); sysreg_restore_guest_state_vhe(guest_ctxt); __debug_switch_to_guest(vcpu); @@ -375,7 +370,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu) } while (fixup_guest_exit(vcpu, &exit_code)); sysreg_save_guest_state_vhe(guest_ctxt); - __sysreg32_save_state(vcpu); __vgic_save_state(vcpu); __deactivate_traps(vcpu); diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c index 479de0f0dd07..65abf1aeba59 100644 --- a/arch/arm64/kvm/hyp/sysreg-sr.c +++ b/arch/arm64/kvm/hyp/sysreg-sr.c @@ -25,8 +25,12 @@ /* * Non-VHE: Both host and guest must save everything. * - * VHE: Host must save tpidr*_el0, actlr_el1, mdscr_el1, sp_el0, - * and guest must save everything. + * VHE: Host and guest must save mdscr_el1 and sp_el0 (and the PC and pstate, + * which are handled as part of the el2 return state) on every switch. + * tpidr_el0, tpidrro_el0, and actlr_el1 only need to be switched when going + * to host userspace or a different VCPU. EL1 registers only need to be + * switched when potentially going to run a different VCPU. The latter two + * classes are handled as part of kvm_arch_vcpu_load and kvm_arch_vcpu_put. */ static void __hyp_text __sysreg_save_common_state(struct kvm_cpu_context *ctxt) @@ -90,14 +94,11 @@ void __hyp_text __sysreg_save_state_nvhe(struct kvm_cpu_context *ctxt) void sysreg_save_host_state_vhe(struct kvm_cpu_context *ctxt) { __sysreg_save_common_state(ctxt); - __sysreg_save_user_state(ctxt); } void sysreg_save_guest_state_vhe(struct kvm_cpu_context *ctxt) { - __sysreg_save_el1_state(ctxt); __sysreg_save_common_state(ctxt); - __sysreg_save_user_state(ctxt); __sysreg_save_el2_return_state(ctxt); } @@ -163,14 +164,11 @@ void __hyp_text __sysreg_restore_state_nvhe(struct kvm_cpu_context *ctxt) void sysreg_restore_host_state_vhe(struct kvm_cpu_context *ctxt) { __sysreg_restore_common_state(ctxt); - __sysreg_restore_user_state(ctxt); } void sysreg_restore_guest_state_vhe(struct kvm_cpu_context *ctxt) { - __sysreg_restore_el1_state(ctxt); __sysreg_restore_common_state(ctxt); - __sysreg_restore_user_state(ctxt); __sysreg_restore_el2_return_state(ctxt); } @@ -236,6 +234,26 @@ void __hyp_text __sysreg32_restore_state(struct kvm_vcpu *vcpu) */ void kvm_vcpu_load_sysregs(struct kvm_vcpu *vcpu) { + struct kvm_cpu_context *host_ctxt = vcpu->arch.host_cpu_context; + struct kvm_cpu_context *guest_ctxt = &vcpu->arch.ctxt; + + if (!has_vhe()) + return; + + __sysreg_save_user_state(host_ctxt); + + + /* + * Load guest EL1 and user state + * + * We must restore the 32-bit state before the sysregs, thanks + * to erratum #852523 (Cortex-A57) or #853709 (Cortex-A72). + */ + __sysreg32_restore_state(vcpu); + __sysreg_restore_user_state(guest_ctxt); + __sysreg_restore_el1_state(guest_ctxt); + + vcpu->arch.sysregs_loaded_on_cpu = true; } /** @@ -264,6 +282,18 @@ void kvm_vcpu_put_sysregs(struct kvm_vcpu *vcpu) __fpsimd_restore_state(&host_ctxt->gp_regs.fp_regs); vcpu->arch.guest_vfp_loaded = 0; } + + if (!has_vhe()) + return; + + __sysreg_save_el1_state(guest_ctxt); + __sysreg_save_user_state(guest_ctxt); + __sysreg32_save_state(vcpu); + + /* Restore host user state */ + __sysreg_restore_user_state(host_ctxt); + + vcpu->arch.sysregs_loaded_on_cpu = false; } void __hyp_text __kvm_set_tpidr_el2(u64 tpidr_el2)