Received: by 2002:ac0:a594:0:0:0:0:0 with SMTP id m20-v6csp1037265imm; Mon, 21 May 2018 20:01:14 -0700 (PDT) X-Google-Smtp-Source: AB8JxZqCf5N+QIKQCnLI58UNbCgyer+gR/YAtCD7AWrtm8n77D5Qb0wk2vUV5JVmud2HXA3lCtqe X-Received: by 2002:a63:7c0b:: with SMTP id x11-v6mr17348094pgc.384.1526958074036; Mon, 21 May 2018 20:01:14 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1526958074; cv=none; d=google.com; s=arc-20160816; b=DBWT2NNxPWgw0Nvjee2aRU3spnSnmiIIuoBb7MTKB1qtyb/6b8tvsouvyPBIuk2cjQ HRlgrO4VDWKlBfiHdYfryvdeElFCD/Z4mdl9om/neWQW0lGOvL7TYc1X5HvBahKwkeP7 KQJo0nkl3yInSQnnX4aMRifmj/x8Y1plx3sOosJk5vphsUt7hBHrglc5lrOdf48XlHFy JUJs7x3IDjUCb1yfNKRx8Bqlpz8FMBmCWiQV1ErTY1wsGqeg0UNPKAi6tlqtseS8Rfjd yKuv2ukCUcE5HnfMvVOcZqz9y/gz2y1VnP0e0Vu40/tuQkYTsJEhdhWcErqZKVJU0fzV QZfg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:arc-authentication-results; bh=YQCX7zPxfZ5TQJe6yyvwdib90XEqUQo5UJvGnjayI1k=; b=sFHjz4D1s24FVVslDVeJf+EpCmGBGg9OzSx5L5F27tUKkjxA4Et21SKH3n4atPgsSL ADqfuOgOYSFSxNGl0Wgl0iA2BhM3qL+6RXTpDCMRQzXCEtTHdO3APBjSYh4IevOS5WdR 39kfc0xVBue5KNDT1U+9M01hQgnLLrjcI5IB0wtX3hqvA0m+u2dSTOrWr2HYdONXabuH vDQ8gIo3Yv5evbHqkOIqu8cKeJ0jCZf4pZfHiWODPQoeZz0u6qd3fnHEbMD8Yu3Zj+DO eypOY1k2ozaA8WuQOO7apfbYKzfYZ3cc4C8wQheN8qjFS2jvpX2PePrNVlVnyaYOhHdt 5rPw== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=intel.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id y12-v6si15556827plt.233.2018.05.21.20.00.59; Mon, 21 May 2018 20:01:14 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=intel.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752803AbeEVC6y (ORCPT + 99 others); Mon, 21 May 2018 22:58:54 -0400 Received: from mga14.intel.com ([192.55.52.115]:13662 "EHLO mga14.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752791AbeEVC6u (ORCPT ); Mon, 21 May 2018 22:58:50 -0400 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga004.jf.intel.com ([10.7.209.38]) by fmsmga103.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 21 May 2018 19:58:49 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.49,428,1520924400"; d="scan'208";a="201336034" Received: from skx-d.bj.intel.com ([10.238.154.68]) by orsmga004.jf.intel.com with ESMTP; 21 May 2018 19:58:44 -0700 From: Luwei Kang To: kvm@vger.kernel.org Cc: tglx@linutronix.de, mingo@redhat.com, hpa@zytor.com, x86@kernel.org, chao.p.peng@linux.intel.com, thomas.lendacky@amd.com, bp@suse.de, Kan.liang@intel.com, Janakarajan.Natarajan@amd.com, dwmw@amazon.co.uk, linux-kernel@vger.kernel.org, alexander.shishkin@linux.intel.com, peterz@infradead.org, mathieu.poirier@linaro.org, kstewart@linuxfoundation.org, gregkh@linuxfoundation.org, pbonzini@redhat.com, rkrcmar@redhat.com, david@redhat.com, bsd@redhat.com, yu.c.zhang@linux.intel.com, joro@8bytes.org, Luwei Kang Subject: [PATCH v9 10/12] KVM: x86: Implement Intel Processor Trace MSRs read/write emulation Date: Tue, 22 May 2018 12:52:13 +0800 Message-Id: <1526964735-16566-11-git-send-email-luwei.kang@intel.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1526964735-16566-1-git-send-email-luwei.kang@intel.com> References: <1526964735-16566-1-git-send-email-luwei.kang@intel.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Chao Peng This patch implement Intel Processor Trace MSRs read/write emulation. Intel PT MSRs read/write need to be emulated when Intel PT MSRs is intercepted in guest and during live migration. Signed-off-by: Chao Peng Signed-off-by: Luwei Kang --- arch/x86/include/asm/intel_pt.h | 8 ++ arch/x86/kvm/vmx.c | 172 ++++++++++++++++++++++++++++++++++++++++ arch/x86/kvm/x86.c | 33 +++++++- 3 files changed, 212 insertions(+), 1 deletion(-) diff --git a/arch/x86/include/asm/intel_pt.h b/arch/x86/include/asm/intel_pt.h index 70f4139..3a25dc1 100644 --- a/arch/x86/include/asm/intel_pt.h +++ b/arch/x86/include/asm/intel_pt.h @@ -10,6 +10,14 @@ #define RTIT_ADDR_RANGE 4 +#define MSR_IA32_RTIT_STATUS_MASK (~(RTIT_STATUS_FILTEREN | \ + RTIT_STATUS_CONTEXTEN | RTIT_STATUS_TRIGGEREN | \ + RTIT_STATUS_ERROR | RTIT_STATUS_STOPPED | \ + RTIT_STATUS_BYTECNT)) + +#define MSR_IA32_RTIT_OUTPUT_BASE_MASK \ + (~((1UL << cpuid_query_maxphyaddr(vcpu)) - 1) | 0x7f) + enum pt_capabilities { PT_CAP_max_subleaf = 0, PT_CAP_cr3_filtering, diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 952ddf4..770cb7c 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -2809,6 +2809,77 @@ static void vmx_set_interrupt_shadow(struct kvm_vcpu *vcpu, int mask) vmcs_write32(GUEST_INTERRUPTIBILITY_INFO, interruptibility); } +static int vmx_rtit_ctl_check(struct kvm_vcpu *vcpu, u64 data) +{ + struct vcpu_vmx *vmx = to_vmx(vcpu); + unsigned long value; + + /* + * Any MSR write that attempts to change bits marked reserved will + * case a #GP fault. + */ + if (data & vmx->pt_desc.ctl_bitmask) + return 1; + + /* + * Any attempt to modify IA32_RTIT_CTL while TraceEn is set will + * result in a #GP unless the same write also clears TraceEn. + */ + if ((vmx->pt_desc.guest.ctl & RTIT_CTL_TRACEEN) && + ((vmx->pt_desc.guest.ctl ^ data) & ~RTIT_CTL_TRACEEN)) + return 1; + + /* + * WRMSR to IA32_RTIT_CTL that sets TraceEn but clears this bit + * and FabricEn would cause #GP, if + * CPUID.(EAX=14H, ECX=0):ECX.SNGLRGNOUT[bit 2] = 0 + */ + if ((data & RTIT_CTL_TRACEEN) && !(data & RTIT_CTL_TOPA) && + !(data & RTIT_CTL_FABRIC_EN) && + !pt_cap_decode(vmx->pt_desc.caps, PT_CAP_single_range_output)) + return 1; + + /* + * MTCFreq, CycThresh and PSBFreq encodings check, any MSR write that + * utilize encodings marked reserved will casue a #GP fault. + */ + value = pt_cap_decode(vmx->pt_desc.caps, PT_CAP_mtc_periods); + if (pt_cap_decode(vmx->pt_desc.caps, PT_CAP_mtc) && + !test_bit((data & RTIT_CTL_MTC_RANGE) >> + RTIT_CTL_MTC_RANGE_OFFSET, &value)) + return 1; + value = pt_cap_decode(vmx->pt_desc.caps, PT_CAP_cycle_thresholds); + if (pt_cap_decode(vmx->pt_desc.caps, PT_CAP_psb_cyc) && + !test_bit((data & RTIT_CTL_CYC_THRESH) >> + RTIT_CTL_CYC_THRESH_OFFSET, &value)) + return 1; + value = pt_cap_decode(vmx->pt_desc.caps, PT_CAP_psb_periods); + if (pt_cap_decode(vmx->pt_desc.caps, PT_CAP_psb_cyc) && + !test_bit((data & RTIT_CTL_PSB_FREQ) >> + RTIT_CTL_PSB_FREQ_OFFSET, &value)) + return 1; + + /* + * If ADDRx_CFG is reserved or the encodings is >2 will + * cause a #GP fault. + */ + value = (data & RTIT_CTL_ADDR0) >> RTIT_CTL_ADDR0_OFFSET; + if ((value && (vmx->pt_desc.addr_range < 1)) || (value > 2)) + return 1; + value = (data & RTIT_CTL_ADDR1) >> RTIT_CTL_ADDR1_OFFSET; + if ((value && (vmx->pt_desc.addr_range < 2)) || (value > 2)) + return 1; + value = (data & RTIT_CTL_ADDR2) >> RTIT_CTL_ADDR2_OFFSET; + if ((value && (vmx->pt_desc.addr_range < 3)) || (value > 2)) + return 1; + value = (data & RTIT_CTL_ADDR3) >> RTIT_CTL_ADDR3_OFFSET; + if ((value && (vmx->pt_desc.addr_range < 4)) || (value > 2)) + return 1; + + return 0; +} + + static void skip_emulated_instruction(struct kvm_vcpu *vcpu) { unsigned long rip; @@ -3625,6 +3696,7 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) { struct vcpu_vmx *vmx = to_vmx(vcpu); struct shared_msr_entry *msr; + u32 index; switch (msr_info->index) { #ifdef CONFIG_X86_64 @@ -3691,6 +3763,51 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) return 1; msr_info->data = vcpu->arch.ia32_xss; break; + case MSR_IA32_RTIT_CTL: + if (pt_mode != PT_MODE_HOST_GUEST) + return 1; + msr_info->data = vmx->pt_desc.guest.ctl; + break; + case MSR_IA32_RTIT_STATUS: + if (pt_mode != PT_MODE_HOST_GUEST) + return 1; + msr_info->data = vmx->pt_desc.guest.status; + break; + case MSR_IA32_RTIT_CR3_MATCH: + if ((pt_mode != PT_MODE_HOST_GUEST) || + !pt_cap_decode(vmx->pt_desc.caps, PT_CAP_cr3_filtering)) + return 1; + msr_info->data = vmx->pt_desc.guest.cr3_match; + break; + case MSR_IA32_RTIT_OUTPUT_BASE: + if ((pt_mode != PT_MODE_HOST_GUEST) || + (!pt_cap_decode(vmx->pt_desc.caps, + PT_CAP_topa_output) && + !pt_cap_decode(vmx->pt_desc.caps, + PT_CAP_single_range_output))) + return 1; + msr_info->data = vmx->pt_desc.guest.output_base; + break; + case MSR_IA32_RTIT_OUTPUT_MASK: + if ((pt_mode != PT_MODE_HOST_GUEST) || + (!pt_cap_decode(vmx->pt_desc.caps, + PT_CAP_topa_output) && + !pt_cap_decode(vmx->pt_desc.caps, + PT_CAP_single_range_output))) + return 1; + msr_info->data = vmx->pt_desc.guest.output_mask; + break; + case MSR_IA32_RTIT_ADDR0_A ... MSR_IA32_RTIT_ADDR3_B: + index = msr_info->index - MSR_IA32_RTIT_ADDR0_A; + if ((pt_mode != PT_MODE_HOST_GUEST) || + (index >= 2 * pt_cap_decode(vmx->pt_desc.caps, + PT_CAP_num_address_ranges))) + return 1; + if (index % 2) + msr_info->data = vmx->pt_desc.guest.addr_b[index / 2]; + else + msr_info->data = vmx->pt_desc.guest.addr_a[index / 2]; + break; case MSR_TSC_AUX: if (!msr_info->host_initiated && !guest_cpuid_has(vcpu, X86_FEATURE_RDTSCP)) @@ -3722,6 +3839,7 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) int ret = 0; u32 msr_index = msr_info->index; u64 data = msr_info->data; + u32 index; switch (msr_index) { case MSR_EFER: @@ -3876,6 +3994,60 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) else clear_atomic_switch_msr(vmx, MSR_IA32_XSS); break; + case MSR_IA32_RTIT_CTL: + if ((pt_mode != PT_MODE_HOST_GUEST) || + vmx_rtit_ctl_check(vcpu, data)) + return 1; + vmcs_write64(GUEST_IA32_RTIT_CTL, data); + vmx->pt_desc.guest.ctl = data; + break; + case MSR_IA32_RTIT_STATUS: + if ((pt_mode != PT_MODE_HOST_GUEST) || + (vmx->pt_desc.guest.ctl & RTIT_CTL_TRACEEN) || + (data & MSR_IA32_RTIT_STATUS_MASK)) + return 1; + vmx->pt_desc.guest.status = data; + break; + case MSR_IA32_RTIT_CR3_MATCH: + if ((pt_mode != PT_MODE_HOST_GUEST) || + (vmx->pt_desc.guest.ctl & RTIT_CTL_TRACEEN) || + !pt_cap_decode(vmx->pt_desc.caps, PT_CAP_cr3_filtering)) + return 1; + vmx->pt_desc.guest.cr3_match = data; + break; + case MSR_IA32_RTIT_OUTPUT_BASE: + if ((pt_mode != PT_MODE_HOST_GUEST) || + (vmx->pt_desc.guest.ctl & RTIT_CTL_TRACEEN) || + (!pt_cap_decode(vmx->pt_desc.caps, + PT_CAP_topa_output) && + !pt_cap_decode(vmx->pt_desc.caps, + PT_CAP_single_range_output)) || + (data & MSR_IA32_RTIT_OUTPUT_BASE_MASK)) + return 1; + vmx->pt_desc.guest.output_base = data; + break; + case MSR_IA32_RTIT_OUTPUT_MASK: + if ((pt_mode != PT_MODE_HOST_GUEST) || + (vmx->pt_desc.guest.ctl & RTIT_CTL_TRACEEN) || + (!pt_cap_decode(vmx->pt_desc.caps, + PT_CAP_topa_output) && + !pt_cap_decode(vmx->pt_desc.caps, + PT_CAP_single_range_output))) + return 1; + vmx->pt_desc.guest.output_mask = data; + break; + case MSR_IA32_RTIT_ADDR0_A ... MSR_IA32_RTIT_ADDR3_B: + index = msr_info->index - MSR_IA32_RTIT_ADDR0_A; + if ((pt_mode != PT_MODE_HOST_GUEST) || + (vmx->pt_desc.guest.ctl & RTIT_CTL_TRACEEN) || + (index >= 2 * pt_cap_decode(vmx->pt_desc.caps, + PT_CAP_num_address_ranges))) + return 1; + if (index % 2) + vmx->pt_desc.guest.addr_b[index / 2] = data; + else + vmx->pt_desc.guest.addr_a[index / 2] = data; + break; case MSR_TSC_AUX: if (!msr_info->host_initiated && !guest_cpuid_has(vcpu, X86_FEATURE_RDTSCP)) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 182693f..8f3d465 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -69,6 +69,7 @@ #include #include #include +#include #define CREATE_TRACE_POINTS #include "trace.h" @@ -1030,7 +1031,13 @@ bool kvm_rdpmc(struct kvm_vcpu *vcpu) #endif MSR_IA32_TSC, MSR_IA32_CR_PAT, MSR_VM_HSAVE_PA, MSR_IA32_FEATURE_CONTROL, MSR_IA32_BNDCFGS, MSR_TSC_AUX, - MSR_IA32_SPEC_CTRL, MSR_IA32_ARCH_CAPABILITIES + MSR_IA32_SPEC_CTRL, MSR_IA32_ARCH_CAPABILITIES, + MSR_IA32_RTIT_CTL, MSR_IA32_RTIT_STATUS, MSR_IA32_RTIT_CR3_MATCH, + MSR_IA32_RTIT_OUTPUT_BASE, MSR_IA32_RTIT_OUTPUT_MASK, + MSR_IA32_RTIT_ADDR0_A, MSR_IA32_RTIT_ADDR0_B, + MSR_IA32_RTIT_ADDR1_A, MSR_IA32_RTIT_ADDR1_B, + MSR_IA32_RTIT_ADDR2_A, MSR_IA32_RTIT_ADDR2_B, + MSR_IA32_RTIT_ADDR3_A, MSR_IA32_RTIT_ADDR3_B, }; static unsigned num_msrs_to_save; @@ -4599,6 +4606,30 @@ static void kvm_init_msr_list(void) if (!kvm_x86_ops->rdtscp_supported()) continue; break; + case MSR_IA32_RTIT_CTL: + case MSR_IA32_RTIT_STATUS: + if (!kvm_x86_ops->pt_supported()) + continue; + break; + case MSR_IA32_RTIT_CR3_MATCH: + if (!kvm_x86_ops->pt_supported() || + !pt_cap_get(PT_CAP_cr3_filtering)) + continue; + break; + case MSR_IA32_RTIT_OUTPUT_BASE: + case MSR_IA32_RTIT_OUTPUT_MASK: + if (!kvm_x86_ops->pt_supported() || + (!pt_cap_get(PT_CAP_topa_output) && + !pt_cap_get(PT_CAP_single_range_output))) + continue; + break; + case MSR_IA32_RTIT_ADDR0_A ... MSR_IA32_RTIT_ADDR3_B: { + if (!kvm_x86_ops->pt_supported() || + msrs_to_save[i] - MSR_IA32_RTIT_ADDR0_A >= + 2 * pt_cap_get(PT_CAP_num_address_ranges)) + continue; + break; + } default: break; } -- 1.8.3.1