From patchwork Thu Dec 1 19:32:05 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jintack Lim X-Patchwork-Id: 9456751 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 0F54B60585 for ; Thu, 1 Dec 2016 19:34:26 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E5CB728541 for ; Thu, 1 Dec 2016 19:34:25 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id D88B928545; Thu, 1 Dec 2016 19:34:25 +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=-3.7 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, RCVD_IN_SORBS_SPAM autolearn=unavailable version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id E1CA128541 for ; Thu, 1 Dec 2016 19:34:23 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.85_2 #1 (Red Hat Linux)) id 1cCX68-0000or-2T; Thu, 01 Dec 2016 19:32:48 +0000 Received: from outprodmail02.cc.columbia.edu ([128.59.72.51]) by bombadil.infradead.org with esmtps (Exim 4.85_2 #1 (Red Hat Linux)) id 1cCX5v-0000UI-Oy for linux-arm-kernel@lists.infradead.org; Thu, 01 Dec 2016 19:32:41 +0000 Received: from hazelnut (hazelnut.cc.columbia.edu [128.59.213.250]) by outprodmail02.cc.columbia.edu (8.14.4/8.14.4) with ESMTP id uB1JS5eT026999 for ; Thu, 1 Dec 2016 14:32:14 -0500 Received: from hazelnut (localhost.localdomain [127.0.0.1]) by hazelnut (Postfix) with ESMTP id B71D18B for ; Thu, 1 Dec 2016 14:32:14 -0500 (EST) Received: from sendprodmail01.cc.columbia.edu (sendprodmail01.cc.columbia.edu [128.59.72.13]) by hazelnut (Postfix) with ESMTP id 7E0048E for ; Thu, 1 Dec 2016 14:32:14 -0500 (EST) Received: from mail-qt0-f199.google.com (mail-qt0-f199.google.com [209.85.216.199]) by sendprodmail01.cc.columbia.edu (8.14.4/8.14.4) with ESMTP id uB1JWEN9011309 (version=TLSv1/SSLv3 cipher=AES128-GCM-SHA256 bits=128 verify=NOT) for ; Thu, 1 Dec 2016 14:32:14 -0500 Received: by mail-qt0-f199.google.com with SMTP id n6so158340674qtd.4 for ; Thu, 01 Dec 2016 11:32:14 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=gQJdzjBOtdL+cdVxxx6j253XVJwf1++FQ0O5uFw7tMo=; b=X+FeBGSLsWP1eEJnnibsrZrVVENPQU5WRaC9Pn93EzU0PEVc7Sm2QAcZlV30WNn8A1 ZisADzDN4zEjIFBT3M7DOXPvZHtxOj9HWDzGgmbLwB2XSGAfvC8QhuBjiWj1KH4Dkhaw Qm9oGb1/bpP93C69Zk6E/IbUtyIK+YTpuVuFkaBkFpXuDouKEopdfYETAeUkRzcjouYL BsRSkxx2a3NmEwB1xPgZoKhY/ySYf1ZXi4aTYfsPR0x/VQRdX7FCogBeNdRYOBfHffkH 60mXUq8+X/gRLltPJw3L9PPYYBoxIq51QElt/i4ywuXtenPRIxLVKOnAm/4JTmc1xwhu ZqLA== X-Gm-Message-State: AKaTC00q84e+QiT5mYrV8H6fvC/awsPtT5UKFYUQryZKX3w70EiSZQBlogY442maAajYl45CCFTuxm6kqEBJ9V0gsW9WBXVPQfSOB0Pshmdk3sxfg3FCq5SSnUo0ehIpfVNRO0qsJNbHJDjaEr+HXwbj0duYgiiOUxA/KQ== X-Received: by 10.200.37.52 with SMTP id 49mr33868295qtm.240.1480620733702; Thu, 01 Dec 2016 11:32:13 -0800 (PST) X-Received: by 10.200.37.52 with SMTP id 49mr33868267qtm.240.1480620733376; Thu, 01 Dec 2016 11:32:13 -0800 (PST) Received: from jintack.cs.columbia.edu ([2001:18d8:ffff:16:21a:4aff:feaa:f900]) by smtp.gmail.com with ESMTPSA id t7sm849763qtd.13.2016.12.01.11.32.12 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 01 Dec 2016 11:32:12 -0800 (PST) From: Jintack Lim To: kvmarm@lists.cs.columbia.edu Subject: [PATCH v3] KVM: arm/arm64: Access CNTHCTL_EL2 bit fields correctly Date: Thu, 1 Dec 2016 14:32:05 -0500 Message-Id: <1480620725-9864-1-git-send-email-jintack@cs.columbia.edu> X-Mailer: git-send-email 1.9.1 X-No-Spam-Score: Local X-Scanned-By: MIMEDefang 2.78 on 128.59.72.13 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20161201_113236_120916_99DA9EC4 X-CRM114-Status: GOOD ( 17.59 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: mark.rutland@arm.com, kvm@vger.kernel.org, rkrcmar@redhat.com, marc.zyngier@arm.com, andre.przywara@arm.com, suzuki.poulose@arm.com, will.deacon@arm.com, linux@armlinux.org.uk, geoff@infradead.org, james.morse@arm.com, linux-arm-kernel@lists.infradead.org, catalin.marinas@arm.com, pbonzini@redhat.com, Jintack Lim , christoffer.dall@linaro.org MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP Current KVM world switch code is unintentionally setting wrong bits to CNTHCTL_EL2 when E2H == 1, which may allow guest OS to access physical timer. Bit positions of CNTHCTL_EL2 are changing depending on HCR_EL2.E2H bit. EL1PCEN and EL1PCTEN are 1st and 0th bits when E2H is not set, but they are 11th and 10th bits respectively when E2H is set. In fact, on VHE we only need to set those bits once, not for every world switch. This is because the host kernel runs in EL2 with HCR_EL2.TGE == 1, which makes those bits have no effect for the host kernel execution. So we just set those bits once for guests, and that's it. Signed-off-by: Jintack Lim Acked-by: Marc Zyngier Reviewed-by: Christoffer Dall --- v2->v3: - Perform the initialization including CPU hotplug case. - Move has_vhe() to asm/virt.h v1->v2: - Skip configuring cnthctl_el2 in world switch path on VHE system. - Write patch based on linux-next. --- arch/arm/include/asm/virt.h | 5 +++++ arch/arm/kvm/arm.c | 3 +++ arch/arm64/include/asm/virt.h | 10 ++++++++++ include/kvm/arm_arch_timer.h | 1 + virt/kvm/arm/arch_timer.c | 23 +++++++++++++++++++++++ virt/kvm/arm/hyp/timer-sr.c | 33 +++++++++++++++++++++------------ 6 files changed, 63 insertions(+), 12 deletions(-) diff --git a/arch/arm/include/asm/virt.h b/arch/arm/include/asm/virt.h index a2e75b8..6dae195 100644 --- a/arch/arm/include/asm/virt.h +++ b/arch/arm/include/asm/virt.h @@ -80,6 +80,11 @@ static inline bool is_kernel_in_hyp_mode(void) return false; } +static inline bool has_vhe(void) +{ + return false; +} + /* The section containing the hypervisor idmap text */ extern char __hyp_idmap_text_start[]; extern char __hyp_idmap_text_end[]; diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index 8f92efa..13e54e8 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -1099,6 +1099,9 @@ static void cpu_init_hyp_mode(void *dummy) __cpu_init_hyp_mode(pgd_ptr, hyp_stack_ptr, vector_ptr); __cpu_init_stage2(); + if (is_kernel_in_hyp_mode()) + kvm_timer_init_vhe(); + kvm_arm_init_debug(); } diff --git a/arch/arm64/include/asm/virt.h b/arch/arm64/include/asm/virt.h index fea1073..b043cfd 100644 --- a/arch/arm64/include/asm/virt.h +++ b/arch/arm64/include/asm/virt.h @@ -47,6 +47,7 @@ #include #include #include +#include /* * __boot_cpu_mode records what mode CPUs were booted in. @@ -80,6 +81,15 @@ static inline bool is_kernel_in_hyp_mode(void) return read_sysreg(CurrentEL) == CurrentEL_EL2; } +static inline bool has_vhe(void) +{ +#ifdef CONFIG_ARM64_VHE + if (cpus_have_const_cap(ARM64_HAS_VIRT_HOST_EXTN)) + return true; +#endif + return false; +} + #ifdef CONFIG_ARM64_VHE extern void verify_cpu_run_el(void); #else diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h index dda39d8..2d54903 100644 --- a/include/kvm/arm_arch_timer.h +++ b/include/kvm/arm_arch_timer.h @@ -76,4 +76,5 @@ int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu, void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu); +void kvm_timer_init_vhe(void); #endif diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c index 17b8fa5..c7c3bfd 100644 --- a/virt/kvm/arm/arch_timer.c +++ b/virt/kvm/arm/arch_timer.c @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -507,3 +508,25 @@ void kvm_timer_init(struct kvm *kvm) { kvm->arch.timer.cntvoff = kvm_phys_timer_read(); } + +/* + * On VHE system, we only need to configure trap on physical timer and counter + * accesses in EL0 and EL1 once, not for every world switch. + * The host kernel runs at EL2 with HCR_EL2.TGE == 1, + * and this makes those bits have no effect for the host kernel execution. + */ +void kvm_timer_init_vhe(void) +{ + /* When HCR_EL2.E2H ==1, EL1PCEN and EL1PCTEN are shifted by 10 */ + u32 cnthctl_shift = 10; + u64 val; + + /* + * Disallow physical timer access for the guest. + * Physical counter access is allowed. + */ + val = read_sysreg(cnthctl_el2); + val &= ~(CNTHCTL_EL1PCEN << cnthctl_shift); + val |= (CNTHCTL_EL1PCTEN << cnthctl_shift); + write_sysreg(val, cnthctl_el2); +} diff --git a/virt/kvm/arm/hyp/timer-sr.c b/virt/kvm/arm/hyp/timer-sr.c index 798866a..63e28dd 100644 --- a/virt/kvm/arm/hyp/timer-sr.c +++ b/virt/kvm/arm/hyp/timer-sr.c @@ -35,10 +35,16 @@ void __hyp_text __timer_save_state(struct kvm_vcpu *vcpu) /* Disable the virtual timer */ write_sysreg_el0(0, cntv_ctl); - /* Allow physical timer/counter access for the host */ - val = read_sysreg(cnthctl_el2); - val |= CNTHCTL_EL1PCTEN | CNTHCTL_EL1PCEN; - write_sysreg(val, cnthctl_el2); + /* + * We don't need to do this for VHE since the host kernel runs in EL2 + * with HCR_EL2.TGE ==1, which makes those bits have no impact. + */ + if (!has_vhe()) { + /* Allow physical timer/counter access for the host */ + val = read_sysreg(cnthctl_el2); + val |= CNTHCTL_EL1PCTEN | CNTHCTL_EL1PCEN; + write_sysreg(val, cnthctl_el2); + } /* Clear cntvoff for the host */ write_sysreg(0, cntvoff_el2); @@ -50,14 +56,17 @@ void __hyp_text __timer_restore_state(struct kvm_vcpu *vcpu) struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu; u64 val; - /* - * Disallow physical timer access for the guest - * Physical counter access is allowed - */ - val = read_sysreg(cnthctl_el2); - val &= ~CNTHCTL_EL1PCEN; - val |= CNTHCTL_EL1PCTEN; - write_sysreg(val, cnthctl_el2); + /* Those bits are already configured at boot on VHE-system */ + if (!has_vhe()) { + /* + * Disallow physical timer access for the guest + * Physical counter access is allowed + */ + val = read_sysreg(cnthctl_el2); + val &= ~CNTHCTL_EL1PCEN; + val |= CNTHCTL_EL1PCTEN; + write_sysreg(val, cnthctl_el2); + } if (timer->enabled) { write_sysreg(kvm->arch.timer.cntvoff, cntvoff_el2);