Received: by 2002:a25:868d:0:0:0:0:0 with SMTP id z13csp1150847ybk; Thu, 14 May 2020 01:33:29 -0700 (PDT) X-Google-Smtp-Source: ABdhPJxsEUBmqvt5VB9SfjDb/FjSc+1WDijXDIa+zO733YC5mEXFT7EKvWSLd4qmyKkHhy4O0q0N X-Received: by 2002:aa7:c3d7:: with SMTP id l23mr3020607edr.125.1589445208815; Thu, 14 May 2020 01:33:28 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1589445208; cv=none; d=google.com; s=arc-20160816; b=L+eJk7tsVFoo1jbyo9MSxJqtnaKf/VHR56AeSc4AAxRC/jT7FUCooBqtLLLYACJDKt AzG5fuwtnTAFaSDv7TVT7AFys6CH7CAG0zCnp8Xag8WM+B/qKErPZsXgvqP6Q57MbPuY GH4lWVwKol8AM+yQ37OrAgh7cVs/wBBE0RgaUZwXtPxXOTO8S9uwDR9cr2OCbThmmSHj iOE7LPwKY7YU7PFdYBc2CR9hwnn6ANnGBZsxPybm6AmEY249/A+5I1eb4quQ5P+0jpLA pmitOys25HIAIe+KkmPpY46gtJvy7H5JY+NXbHjgnx2xeCYtVsAETEm6mMvFPafFTlNS ymkQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :ironport-sdr:ironport-sdr; bh=6A4mF36/Y42lCnNah75Ml4lom1SPFl4h9aYsCahdwAc=; b=z8tdw1KP88w1RhR/XMWh0IXUHoWR0y1pDSkqwJpUGNNDEIy1aCWsFm5HkCCgiiuG2V H8Gxyoi8G5Wdv3hlo7j1JoKJu9/5nGBA89ljRS4iddfs3YYyz9EEGH3rjeZ14o+OPUNQ 1zGQuNnN7bbcu6LhInQJKaGiOCiV6FAY/TGaROapKyH5dR73zgD+hp7KUb2q4WlU+P+A 72GVVuEBnZ49nBCCC0hxGjhnkk0Pajv5+GAXGPqbDrx4voof0Ry+gBOYNrBiag4+4OVQ wQ2ij0K7p+2wqWiztIWoQGv8wKVX9XMg0wVFU3vNrCmgihEgtDL/v0izhUqBR0Mv7srI UFow== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 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. [23.128.96.18]) by mx.google.com with ESMTP id f12si1432853ejq.227.2020.05.14.01.33.06; Thu, 14 May 2020 01:33:28 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 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 S1726521AbgENIb3 (ORCPT + 99 others); Thu, 14 May 2020 04:31:29 -0400 Received: from mga18.intel.com ([134.134.136.126]:12089 "EHLO mga18.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725970AbgENIb2 (ORCPT ); Thu, 14 May 2020 04:31:28 -0400 IronPort-SDR: ApFl5oTnSLQtVVGrnoV0a6G2r3Ncqs8PoBys6VfYGrD/DMgnyW5TuLw1Hk4/APtl0FPvctdeyY ZPvq+bDUXVCA== X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga001.jf.intel.com ([10.7.209.18]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 May 2020 01:31:27 -0700 IronPort-SDR: Yy5f+09HqVcYBzklsHZ+VH23XQzVL9jta9UM8SqQwCRi24dlzc5Nhjk1aC0KZU16vOPPyQt9NP Jy4R7e27UyTQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.73,390,1583222400"; d="scan'208";a="341539971" Received: from sqa-gate.sh.intel.com (HELO clx-ap-likexu.tsp.org) ([10.239.48.212]) by orsmga001.jf.intel.com with ESMTP; 14 May 2020 01:31:23 -0700 From: Like Xu To: Peter Zijlstra , Paolo Bonzini Cc: linux-kernel@vger.kernel.org, kvm@vger.kernel.org, Sean Christopherson , Vitaly Kuznetsov , Wanpeng Li , Jim Mattson , Joerg Roedel , Thomas Gleixner , ak@linux.intel.com, wei.w.wang@intel.com, Like Xu Subject: [PATCH v11 05/11] perf/x86: Keep LBR stack unchanged in host context for guest LBR event Date: Thu, 14 May 2020 16:30:48 +0800 Message-Id: <20200514083054.62538-6-like.xu@linux.intel.com> X-Mailer: git-send-email 2.21.3 In-Reply-To: <20200514083054.62538-1-like.xu@linux.intel.com> References: <20200514083054.62538-1-like.xu@linux.intel.com> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org When a guest wants to use the LBR stack, its hypervisor creates a guest LBR event and let host perf schedules it. A new 'int guest_lbr_enabled' field in the 'struct cpu_hw_events', is marked as true when perf adds a guest LBR event and marked as false on deletion. The LBR stack msrs are accessible to the guest when its guest LBR event is scheduled in by the perf subsystem. Before scheduling this event out, we should avoid host changes on IA32_DEBUGCTLMSR or LBR_SELECT. Otherwise, some unexpected branch operations may interfere with guest behavior, pollute LBR records, and even cause host branch data leakage. In addition, the intel_pmu_lbr_read() on the host is also avoidable. To ensure that guest LBR records are not lost during the context switch, the BRANCH_CALL_STACK flag should be configured in the 'branch_sample_type' for any guest LBR event because the callstack mode could save/restore guest unread LBR records with the help of intel_pmu_lbr_sched_task() naturally. However, the regular host LBR perf event doesn't save/restore LBR_SELECT, because it's configured in the LBR_enable() based on branch_sample_type. So when a guest LBR is running, the guest LBR_SELECT may changes for its own use and we have to support LBR_SELECT save/restore to ensure what the guest LBR_SELECT value doesn't get lost during the context switching. Cc: Peter Zijlstra (Intel) Co-developed-by: Wei Wang Signed-off-by: Wei Wang Signed-off-by: Like Xu --- arch/x86/events/intel/lbr.c | 33 ++++++++++++++++++++++++++++++--- arch/x86/events/perf_event.h | 2 ++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/arch/x86/events/intel/lbr.c b/arch/x86/events/intel/lbr.c index 0a91cbe3a7c7..ff8d0433837d 100644 --- a/arch/x86/events/intel/lbr.c +++ b/arch/x86/events/intel/lbr.c @@ -383,6 +383,15 @@ static void __intel_pmu_lbr_restore(struct x86_perf_task_context *task_ctx) wrmsrl(x86_pmu.lbr_tos, tos); task_ctx->lbr_stack_state = LBR_NONE; + + /* + * When the LBR hardware is scheduled for a guest LBR event, + * the guest lbr_sel is likely different from event->hw.branch_reg. + * Therefore, it’s necessary to save/restore MSR_LBR_SELECT written + * by the guest so that it's not lost during the context switch. + */ + if (cpuc->guest_lbr_enabled) + wrmsrl(MSR_LBR_SELECT, task_ctx->lbr_sel); } static void __intel_pmu_lbr_save(struct x86_perf_task_context *task_ctx) @@ -415,6 +424,9 @@ static void __intel_pmu_lbr_save(struct x86_perf_task_context *task_ctx) cpuc->last_task_ctx = task_ctx; cpuc->last_log_id = ++task_ctx->log_id; + + if (cpuc->guest_lbr_enabled) + rdmsrl(MSR_LBR_SELECT, task_ctx->lbr_sel); } void intel_pmu_lbr_swap_task_ctx(struct perf_event_context *prev, @@ -485,6 +497,9 @@ void intel_pmu_lbr_add(struct perf_event *event) if (!x86_pmu.lbr_nr) return; + if (is_guest_lbr_event(event)) + cpuc->guest_lbr_enabled = 1; + cpuc->br_sel = event->hw.branch_reg.reg; if (branch_user_callstack(cpuc->br_sel) && event->ctx->task_ctx_data) { @@ -532,6 +547,9 @@ void intel_pmu_lbr_del(struct perf_event *event) task_ctx->lbr_callstack_users--; } + if (is_guest_lbr_event(event)) + cpuc->guest_lbr_enabled = 0; + if (x86_pmu.intel_cap.pebs_baseline && event->attr.precise_ip > 0) cpuc->lbr_pebs_users--; cpuc->lbr_users--; @@ -544,7 +562,12 @@ void intel_pmu_lbr_enable_all(bool pmi) { struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); - if (cpuc->lbr_users) + /* + * When the LBR hardware is scheduled for a guest LBR event, + * the guest will dis/enables LBR itself at the appropriate time, + * including configuring MSR_LBR_SELECT. + */ + if (cpuc->lbr_users && !cpuc->guest_lbr_enabled) __intel_pmu_lbr_enable(pmi); } @@ -552,7 +575,7 @@ void intel_pmu_lbr_disable_all(void) { struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); - if (cpuc->lbr_users) + if (cpuc->lbr_users && !cpuc->guest_lbr_enabled) __intel_pmu_lbr_disable(); } @@ -693,8 +716,12 @@ void intel_pmu_lbr_read(void) * * This could be smarter and actually check the event, * but this simple approach seems to work for now. + * + * And there is no need to read LBR record here if a guest LBR + * event is using it, because the guest will read them on its own. */ - if (!cpuc->lbr_users || cpuc->lbr_users == cpuc->lbr_pebs_users) + if (!cpuc->lbr_users || cpuc->guest_lbr_enabled || + cpuc->lbr_users == cpuc->lbr_pebs_users) return; if (x86_pmu.intel_cap.lbr_format == LBR_FORMAT_32) diff --git a/arch/x86/events/perf_event.h b/arch/x86/events/perf_event.h index 34d76a2f5ebd..8d322b0204c8 100644 --- a/arch/x86/events/perf_event.h +++ b/arch/x86/events/perf_event.h @@ -237,6 +237,7 @@ struct cpu_hw_events { u64 br_sel; struct x86_perf_task_context *last_task_ctx; int last_log_id; + int guest_lbr_enabled; /* * Intel host/guest exclude bits @@ -721,6 +722,7 @@ struct x86_perf_task_context { u64 lbr_from[MAX_LBR_ENTRIES]; u64 lbr_to[MAX_LBR_ENTRIES]; u64 lbr_info[MAX_LBR_ENTRIES]; + u64 lbr_sel; int tos; int valid_lbrs; int lbr_callstack_users; -- 2.21.3