From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1030886AbcDMLaz (ORCPT ); Wed, 13 Apr 2016 07:30:55 -0400 Received: from terminus.zytor.com ([198.137.202.10]:55586 "EHLO terminus.zytor.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1030724AbcDMLax (ORCPT ); Wed, 13 Apr 2016 07:30:53 -0400 Date: Wed, 13 Apr 2016 04:29:26 -0700 From: tip-bot for Andy Lutomirski Message-ID: Cc: luto@kernel.org, peterz@infradead.org, torvalds@linux-foundation.org, r.marek@assembler.cz, dvlasenk@redhat.com, brgerst@gmail.com, bp@suse.de, hpa@zytor.com, bp@alien8.de, luto@amacapital.net, mingo@kernel.org, tglx@linutronix.de, linux-kernel@vger.kernel.org Reply-To: torvalds@linux-foundation.org, luto@kernel.org, peterz@infradead.org, hpa@zytor.com, r.marek@assembler.cz, dvlasenk@redhat.com, brgerst@gmail.com, bp@suse.de, bp@alien8.de, mingo@kernel.org, luto@amacapital.net, linux-kernel@vger.kernel.org, tglx@linutronix.de In-Reply-To: <61588ba0e0df35beafd363dc8b68a4c5878ef095.1460075211.git.luto@kernel.org> References: <61588ba0e0df35beafd363dc8b68a4c5878ef095.1460075211.git.luto@kernel.org> To: linux-tip-commits@vger.kernel.org Subject: [tip:x86/asm] x86/cpu: Probe the behavior of nulling out a segment at boot time Git-Commit-ID: 7a5d67048745e3eab62779c6d043a2e3d95dc848 X-Mailer: tip-git-log-daemon Robot-ID: Robot-Unsubscribe: Contact to get blacklisted from these emails MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Content-Type: text/plain; charset=UTF-8 Content-Disposition: inline Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Commit-ID: 7a5d67048745e3eab62779c6d043a2e3d95dc848 Gitweb: http://git.kernel.org/tip/7a5d67048745e3eab62779c6d043a2e3d95dc848 Author: Andy Lutomirski AuthorDate: Thu, 7 Apr 2016 17:31:46 -0700 Committer: Ingo Molnar CommitDate: Wed, 13 Apr 2016 10:20:41 +0200 x86/cpu: Probe the behavior of nulling out a segment at boot time AMD and Intel do different things when writing zero to a segment selector. Since neither vendor documents the behavior well and it's easy to test the behavior, try nulling fs to see what happens. Signed-off-by: Andy Lutomirski Reviewed-by: Borislav Petkov Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Rudolf Marek Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/61588ba0e0df35beafd363dc8b68a4c5878ef095.1460075211.git.luto@kernel.org Signed-off-by: Ingo Molnar --- arch/x86/include/asm/cpufeatures.h | 1 + arch/x86/kernel/cpu/common.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h index 8f9afef..2a05230 100644 --- a/arch/x86/include/asm/cpufeatures.h +++ b/arch/x86/include/asm/cpufeatures.h @@ -294,6 +294,7 @@ #define X86_BUG_FXSAVE_LEAK X86_BUG(6) /* FXSAVE leaks FOP/FIP/FOP */ #define X86_BUG_CLFLUSH_MONITOR X86_BUG(7) /* AAI65, CLFLUSH required before MONITOR */ #define X86_BUG_SYSRET_SS_ATTRS X86_BUG(8) /* SYSRET doesn't fix up SS attrs */ +#define X86_BUG_NULL_SEG X86_BUG(9) /* Nulling a selector preserves the base */ #ifdef CONFIG_X86_32 /* diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 7fea407..8e40eee 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -889,6 +889,35 @@ static void detect_nopl(struct cpuinfo_x86 *c) #endif } +static void detect_null_seg_behavior(struct cpuinfo_x86 *c) +{ +#ifdef CONFIG_X86_64 + /* + * Empirically, writing zero to a segment selector on AMD does + * not clear the base, whereas writing zero to a segment + * selector on Intel does clear the base. Intel's behavior + * allows slightly faster context switches in the common case + * where GS is unused by the prev and next threads. + * + * Since neither vendor documents this anywhere that I can see, + * detect it directly instead of hardcoding the choice by + * vendor. + * + * I've designated AMD's behavior as the "bug" because it's + * counterintuitive and less friendly. + */ + + unsigned long old_base, tmp; + rdmsrl(MSR_FS_BASE, old_base); + wrmsrl(MSR_FS_BASE, 1); + loadsegment(fs, 0); + rdmsrl(MSR_FS_BASE, tmp); + if (tmp != 0) + set_cpu_bug(c, X86_BUG_NULL_SEG); + wrmsrl(MSR_FS_BASE, old_base); +#endif +} + static void generic_identify(struct cpuinfo_x86 *c) { c->extended_cpuid_level = 0; @@ -921,6 +950,8 @@ static void generic_identify(struct cpuinfo_x86 *c) get_model_name(c); /* Default name */ detect_nopl(c); + + detect_null_seg_behavior(c); } static void x86_init_cache_qos(struct cpuinfo_x86 *c)