diff options
author | Andy Lutomirski <luto@kernel.org> | 2016-04-07 20:31:46 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2016-04-13 04:20:41 -0400 |
commit | 7a5d67048745e3eab62779c6d043a2e3d95dc848 (patch) | |
tree | c3052c7d6e5b675ced4c3a7edb2f7a6c2c7bb65f /arch/x86/kernel | |
parent | d47b50e7a111bb7a56fb1c974728b56209d7f515 (diff) |
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 <luto@kernel.org>
Reviewed-by: Borislav Petkov <bp@suse.de>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Rudolf Marek <r.marek@assembler.cz>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/61588ba0e0df35beafd363dc8b68a4c5878ef095.1460075211.git.luto@kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'arch/x86/kernel')
-rw-r--r-- | arch/x86/kernel/cpu/common.c | 31 |
1 files changed, 31 insertions, 0 deletions
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 7fea4079d102..8e40eee5843a 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) | |||
889 | #endif | 889 | #endif |
890 | } | 890 | } |
891 | 891 | ||
892 | static void detect_null_seg_behavior(struct cpuinfo_x86 *c) | ||
893 | { | ||
894 | #ifdef CONFIG_X86_64 | ||
895 | /* | ||
896 | * Empirically, writing zero to a segment selector on AMD does | ||
897 | * not clear the base, whereas writing zero to a segment | ||
898 | * selector on Intel does clear the base. Intel's behavior | ||
899 | * allows slightly faster context switches in the common case | ||
900 | * where GS is unused by the prev and next threads. | ||
901 | * | ||
902 | * Since neither vendor documents this anywhere that I can see, | ||
903 | * detect it directly instead of hardcoding the choice by | ||
904 | * vendor. | ||
905 | * | ||
906 | * I've designated AMD's behavior as the "bug" because it's | ||
907 | * counterintuitive and less friendly. | ||
908 | */ | ||
909 | |||
910 | unsigned long old_base, tmp; | ||
911 | rdmsrl(MSR_FS_BASE, old_base); | ||
912 | wrmsrl(MSR_FS_BASE, 1); | ||
913 | loadsegment(fs, 0); | ||
914 | rdmsrl(MSR_FS_BASE, tmp); | ||
915 | if (tmp != 0) | ||
916 | set_cpu_bug(c, X86_BUG_NULL_SEG); | ||
917 | wrmsrl(MSR_FS_BASE, old_base); | ||
918 | #endif | ||
919 | } | ||
920 | |||
892 | static void generic_identify(struct cpuinfo_x86 *c) | 921 | static void generic_identify(struct cpuinfo_x86 *c) |
893 | { | 922 | { |
894 | c->extended_cpuid_level = 0; | 923 | c->extended_cpuid_level = 0; |
@@ -921,6 +950,8 @@ static void generic_identify(struct cpuinfo_x86 *c) | |||
921 | get_model_name(c); /* Default name */ | 950 | get_model_name(c); /* Default name */ |
922 | 951 | ||
923 | detect_nopl(c); | 952 | detect_nopl(c); |
953 | |||
954 | detect_null_seg_behavior(c); | ||
924 | } | 955 | } |
925 | 956 | ||
926 | static void x86_init_cache_qos(struct cpuinfo_x86 *c) | 957 | static void x86_init_cache_qos(struct cpuinfo_x86 *c) |