Received: by 10.213.65.68 with SMTP id h4csp1811415imn; Mon, 19 Mar 2018 13:59:05 -0700 (PDT) X-Google-Smtp-Source: AG47ELtv63J/093aAJ1Uz7IGi3+6AovtBAyNGKw2AQLrgIrzPeq22n1P/TOZXnnsgkVxXvz8ruzd X-Received: by 10.98.171.7 with SMTP id p7mr11043199pff.71.1521493145102; Mon, 19 Mar 2018 13:59:05 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1521493145; cv=none; d=google.com; s=arc-20160816; b=Db/L6aTxHW1KpjNjSXz+bnYJse0/DbH/rj0YPSjTGifTfO8j0h+RbTbGQ3nKG+3bJ6 kAS5rHsLHbq627osd/fi2Pb/KTBfV8mT31bei9IXgD7/8wZGhOAdjP4hurYqP0+nByQp SxW0bYBP0VoLhaIpmhF+iGDAEjn7D80jjqQacu8+FuRVhTI93++JLj5G5HgNmRneXt+p eo90eXGZrkkl1f39OqQMksy4QY8vrOjaRZFXgn3Z2PrPNBeSf4xW4Y/ScO97ol2wS0Xc 18vm1Pfe9hzcHdSzgO0oKXymrMhXlYgz1mztD01tFd6+CKJoUNBOsVwbczo5u67wo0+F RiGQ== 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=duBTwc0NT1QpUAUEQjspeBh1vqcLrnksjK/O47o/PZA=; b=x/p8ppA2dT2kWXvyusm8q0XYHLGlOewXc1vI8OJO1+vRuHj9T6JUIP3ZEscOLdX6/F QowegOxDqVOGn2Eu6p4IawCVPahdPtNXFz8ONsqG3Xh6h7PU40LuwFuRTRZiCH5D5WFo rtmBPmpMb7vRMuBR2BRYpElLWrwmv9EYML2Gsi0rE7zunTPZQENVRpUXbkr+HaqvyHY3 Q+lPqNxe4tw/BwR6LIqg4tYY1Ht1ia21rWcb8bmdg+x1203bnhHF/o/nnm2rnxqnYUfI ibeIQBD8/1QcfLdDmn3X9YC8RKccfh2ErTQKtPAcKHF29c71MDw94zkLd4By7sDv/gG2 SYmA== 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 Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id x12-v6si78265plr.334.2018.03.19.13.58.51; Mon, 19 Mar 2018 13:59:05 -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 Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S971782AbeCSU4f (ORCPT + 99 others); Mon, 19 Mar 2018 16:56:35 -0400 Received: from mga14.intel.com ([192.55.52.115]:62511 "EHLO mga14.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S968530AbeCSSIy (ORCPT ); Mon, 19 Mar 2018 14:08:54 -0400 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by fmsmga103.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 19 Mar 2018 11:08:53 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.48,331,1517904000"; d="scan'208";a="39330592" Received: from chang-linux.sc.intel.com ([143.183.85.144]) by fmsmga001.fm.intel.com with ESMTP; 19 Mar 2018 11:08:53 -0700 From: "Chang S. Bae" To: x86@kernel.org Cc: luto@kernel.org, ak@linux.intel.com, hpa@zytor.com, markus.t.metzger@intel.com, tony.luck@intel.com, ravi.v.shankar@intel.com, linux-kernel@vger.kernel.org, chang.seok.bae@intel.com Subject: [PATCH 10/15] x86/fsgsbase/64: Enable FSGSBASE instructions in helper functions Date: Mon, 19 Mar 2018 10:49:22 -0700 Message-Id: <1521481767-22113-11-git-send-email-chang.seok.bae@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1521481767-22113-1-git-send-email-chang.seok.bae@intel.com> References: <1521481767-22113-1-git-send-email-chang.seok.bae@intel.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The helper functions switch on faster access to FS/GS, when FSGSBASE enabled. Accessing user GS base needs a couple of SWPAGS. It is avoidable if the user GS base is copied at kernel entry and updated as changed, and (actual) GS base is written back at kernel exit. However, it costs more cycles to do that. The measured overhead was (almost) offset to the benefit. Signed-off-by: Chang S. Bae Reviewed-by: Andi Kleen Cc: Any Lutomirski Cc: H. Peter Anvin --- arch/x86/include/asm/fsgsbase.h | 17 ++++------ arch/x86/kernel/process_64.c | 75 +++++++++++++++++++++++++++++++++++------ 2 files changed, 72 insertions(+), 20 deletions(-) diff --git a/arch/x86/include/asm/fsgsbase.h b/arch/x86/include/asm/fsgsbase.h index cad2831..8936b7f 100644 --- a/arch/x86/include/asm/fsgsbase.h +++ b/arch/x86/include/asm/fsgsbase.h @@ -55,6 +55,8 @@ static __always_inline void wrgsbase(unsigned long gsbase) : "memory"); } +#include + /* * Helper functions for reading/writing FS/GS base */ @@ -63,20 +65,15 @@ static inline unsigned long read_fsbase(void) { unsigned long fsbase; - rdmsrl(MSR_FS_BASE, fsbase); + if (static_cpu_has(X86_FEATURE_FSGSBASE)) + fsbase = rdfsbase(); + else + rdmsrl(MSR_FS_BASE, fsbase); return fsbase; } void write_fsbase(unsigned long fsbase); - -static inline unsigned long read_shadow_gsbase(void) -{ - unsigned long gsbase; - - rdmsrl(MSR_KERNEL_GS_BASE, gsbase); - return gsbase; -} - +unsigned long read_shadow_gsbase(void); void write_shadow_gsbase(unsigned long gsbase); #endif /* CONFIG_X86_64 */ diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index 4488f07..877636a 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c @@ -154,6 +154,38 @@ enum which_selector { }; /* + * Interrupts are disabled here. + * Out of line to be protected from kprobes. + */ +static noinline __kprobes unsigned long rd_shadow_gsbase(void) +{ + unsigned long gsbase, flags; + + local_irq_save(flags); + native_swapgs(); + gsbase = rdgsbase(); + native_swapgs(); + local_irq_restore(flags); + + return gsbase; +} + +/* + * Interrupts are disabled here. + * Out of line to be protected from kprobes. + */ +static noinline __kprobes void wr_shadow_gsbase(unsigned long gsbase) +{ + unsigned long flags; + + local_irq_save(flags); + native_swapgs(); + wrgsbase(gsbase); + native_swapgs(); + local_irq_restore(flags); +} + +/* * Saves the FS or GS base for an outgoing thread if FSGSBASE extensions are * not available. The goal is to be reasonably fast on non-FSGSBASE systems. * It's forcibly inlined because it'll generate better code and this function @@ -319,16 +351,35 @@ static unsigned long task_seg_base(struct task_struct *task, void write_fsbase(unsigned long fsbase) { - /* set the selector to 0 to not confuse __switch_to */ - loadseg(FS, 0); - wrmsrl(MSR_FS_BASE, fsbase); + if (static_cpu_has(X86_FEATURE_FSGSBASE)) { + wrfsbase(fsbase); + } else { + /* set the selector to 0 to not confuse __switch_to */ + loadseg(FS, 0); + wrmsrl(MSR_FS_BASE, fsbase); + } +} + +unsigned long read_shadow_gsbase(void) +{ + unsigned long gsbase; + + if (static_cpu_has(X86_FEATURE_FSGSBASE)) + gsbase = rd_shadow_gsbase(); + else + rdmsrl(MSR_KERNEL_GS_BASE, gsbase); + return gsbase; } void write_shadow_gsbase(unsigned long gsbase) { - /* set the selector to 0 to not confuse __switch_to */ - loadseg(GS, 0); - wrmsrl(MSR_KERNEL_GS_BASE, gsbase); + if (static_cpu_has(X86_FEATURE_FSGSBASE)) { + wr_shadow_gsbase(gsbase); + } else { + /* set the selector to 0 to not confuse __switch_to */ + loadseg(GS, 0); + wrmsrl(MSR_KERNEL_GS_BASE, gsbase); + } } unsigned long read_task_fsbase(struct task_struct *task) @@ -337,7 +388,8 @@ unsigned long read_task_fsbase(struct task_struct *task) if (task == current) fsbase = read_fsbase(); - else if (task->thread.fsindex == 0) + else if (static_cpu_has(X86_FEATURE_FSGSBASE) || + (task->thread.fsindex == 0)) fsbase = task->thread.fsbase; else fsbase = task_seg_base(task, task->thread.fsindex); @@ -351,7 +403,8 @@ unsigned long read_task_gsbase(struct task_struct *task) if (task == current) gsbase = read_shadow_gsbase(); - else if (task->thread.gsindex == 0) + else if (static_cpu_has(X86_FEATURE_FSGSBASE) || + (task->thread.gsindex == 0)) gsbase = task->thread.gsbase; else gsbase = task_seg_base(task, task->thread.gsindex); @@ -374,7 +427,8 @@ int write_task_fsbase(struct task_struct *task, unsigned long fsbase) task->thread.fsbase = fsbase; if (task == current) write_fsbase(fsbase); - task->thread.fsindex = 0; + if (!static_cpu_has(X86_FEATURE_FSGSBASE)) + task->thread.fsindex = 0; put_cpu(); return 0; @@ -391,7 +445,8 @@ int write_task_gsbase(struct task_struct *task, unsigned long gsbase) task->thread.gsbase = gsbase; if (task == current) write_shadow_gsbase(gsbase); - task->thread.gsindex = 0; + if (!static_cpu_has(X86_FEATURE_FSGSBASE)) + task->thread.gsindex = 0; put_cpu(); return 0; -- 2.7.4