Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751987AbdHARhu (ORCPT ); Tue, 1 Aug 2017 13:37:50 -0400 Received: from mx1.redhat.com ([209.132.183.28]:43960 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751832AbdHARht (ORCPT ); Tue, 1 Aug 2017 13:37:49 -0400 DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com EF6E7E233A Authentication-Results: ext-mx02.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx02.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=rkrcmar@redhat.com Date: Tue, 1 Aug 2017 19:37:39 +0200 From: Radim =?utf-8?B?S3LEjW3DocWZ?= To: Paolo Bonzini Cc: David Hildenbrand , linux-kernel@vger.kernel.org, kvm@vger.kernel.org Subject: Re: [PATCH] KVM: nVMX: INVPCID support Message-ID: <20170801173739.GA316@flask> References: <1501161639-9707-1-git-send-email-pbonzini@redhat.com> <0b82ca85-7b3e-9dc4-a102-24d0e9033dcd@redhat.com> <42be1e05-b6e4-42db-5ed8-276d61c4334d@redhat.com> <60a8347a-744d-47d3-e53b-3218f5c50623@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.26]); Tue, 01 Aug 2017 17:37:49 +0000 (UTC) Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 2990 Lines: 86 2017-08-01 13:35+0200, Paolo Bonzini: > On 01/08/2017 13:18, David Hildenbrand wrote: > > > >>> Can't we rewrite that a little bit, avoiding that "best" handling > >>> (introducing guest_cpuid_disable_invpcid() and guest_cpuid_has_invpcid()) > >>> > >>> bool invpcid_enabled = guest_cpuid_has_pcid(vcpu) && > >>> guest_cpuid_has_invpcid(); > >>> > >>> if (!invpcid_enabled) { > >>> secondary_exec_ctl &= ~SECONDARY_EXEC_ENABLE_INVPCID; > >>> /* make sure there is no no INVPCID without PCID */ > >>> guest_cpuid_disable_invpcid(vcpu); > >>> } > >> > >> I don't know... if you need a comment, it means the different structure > >> of the code doesn't spare many doubts from the reader. And the code > >> doesn't become much simpler since you have to handle "nested" anyway. > >> What I tried to do was to mimic as much as possible the rdtscp case, but > >> it cannot be exactly the same due to the interaction between PCID and > >> INVPCID. > > > > It's more about the handling of best here, which can be avoided quite > > easily as I showed (by encapsulating how cpuids are looked up/modified). > > Yeah, I don't like either option. :) Luckily there is a second maintainer! With three people, we'll just have three options! :) I'd go with Paolo's version, because it is efficient and also follows patterns the bit clearing in kvm_update_cpuid(). --- I would like the wrappers if they were more generic, e.g.: guest_cpuid_has(vcpu, X86_FEATURE_INVPCID); guest_cpuid_clear(vcpu, X86_FEATURE_INVPCID); To do that, we need a mapping from X86_FEATURE to (leaf, subleaf, register) triple, which can be done with cpuid_leafs. I haven't tried to compile the idea below, but if the optimizer is good, then we should have only slightly worse byte code as we do now thanks to x86_feature being a compile-time constant. Do you it's less ugly than the other two options? static inline bool x86_feature_cpuid(int x86_feature, int *id, int *count, int *register) { static struct {int x86_leaf; int id; int count; int register;} cpuid[] = { {CPUID_1_EDX, 1, 0, 3}, {CPUID_8000_0001_EDX, 0x80000001, 0, 3}, {CPUID_8086_0001_EDX, 0x80860001, 0, 3}, {CPUID_1_ECX, 1, 0, 2}, ... // you get the idea, it's tedious :) }; for (size_t i = 0; i < ARRAY_SIZE(cpuid); i++) if (cpuid[i].x86_leaf == x86_feature / 32) { *id = cpuid[i].id; *count = cpuid[i].count; *register = cpuid[i].register; return true; } return false; } static inline bool guest_cpuid_has(struct kvm_vcpu *vcpu, int x86_feature) { int id, count, register; u32 *reg; struct kvm_cpuid_entry2 *best; if (!x86_feature_cpuid(x86_feature, &id, &count, ®ister)) return false; if (!(best = kvm_find_cpuid_entry(id, count))) return false; reg = &best->eax + register; // rewrite to be safer return *reg & bit(x86_feature); } Similar for guest_cpuid_clear and we can also factor out the common part for getting the register (all up to the last line, with NULL as failure)