-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
x86, boot: Move CPU flags out of cpucheck
Refactor the CPU flags handling out of the cpucheck routines so that they can be reused by the future ASLR routines (in order to detect CPU features like RDRAND and RDTSC). This reworks has_eflag() and has_fpu() to be used on both 32-bit and 64-bit, and refactors the calls to cpuid to make them PIC-safe on 32-bit. Signed-off-by: Kees Cook <keescook@chromium.org> Link: http://lkml.kernel.org/r/1381450698-28710-2-git-send-email-keescook@chromium.org Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
- Loading branch information
Kees Cook
authored and
H. Peter Anvin
committed
Oct 13, 2013
1 parent
d751c16
commit dd78b97
Showing
7 changed files
with
138 additions
and
97 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
#ifdef CONFIG_RANDOMIZE_BASE | ||
|
||
#include "../cpuflags.c" | ||
|
||
bool has_cpuflag(int flag) | ||
{ | ||
get_flags(); | ||
|
||
return test_bit(flag, cpu.flags); | ||
} | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
#include <linux/types.h> | ||
#include "bitops.h" | ||
|
||
#include <asm/processor-flags.h> | ||
#include <asm/required-features.h> | ||
#include <asm/msr-index.h> | ||
#include "cpuflags.h" | ||
|
||
struct cpu_features cpu; | ||
u32 cpu_vendor[3]; | ||
|
||
static bool loaded_flags; | ||
|
||
static int has_fpu(void) | ||
{ | ||
u16 fcw = -1, fsw = -1; | ||
unsigned long cr0; | ||
|
||
asm volatile("mov %%cr0,%0" : "=r" (cr0)); | ||
if (cr0 & (X86_CR0_EM|X86_CR0_TS)) { | ||
cr0 &= ~(X86_CR0_EM|X86_CR0_TS); | ||
asm volatile("mov %0,%%cr0" : : "r" (cr0)); | ||
} | ||
|
||
asm volatile("fninit ; fnstsw %0 ; fnstcw %1" | ||
: "+m" (fsw), "+m" (fcw)); | ||
|
||
return fsw == 0 && (fcw & 0x103f) == 0x003f; | ||
} | ||
|
||
int has_eflag(unsigned long mask) | ||
{ | ||
unsigned long f0, f1; | ||
|
||
asm volatile("pushf \n\t" | ||
"pushf \n\t" | ||
"pop %0 \n\t" | ||
"mov %0,%1 \n\t" | ||
"xor %2,%1 \n\t" | ||
"push %1 \n\t" | ||
"popf \n\t" | ||
"pushf \n\t" | ||
"pop %1 \n\t" | ||
"popf" | ||
: "=&r" (f0), "=&r" (f1) | ||
: "ri" (mask)); | ||
|
||
return !!((f0^f1) & mask); | ||
} | ||
|
||
/* Handle x86_32 PIC using ebx. */ | ||
#if defined(__i386__) && defined(__PIC__) | ||
# define EBX_REG "=r" | ||
#else | ||
# define EBX_REG "=b" | ||
#endif | ||
|
||
static inline void cpuid(u32 id, u32 *a, u32 *b, u32 *c, u32 *d) | ||
{ | ||
asm volatile(".ifnc %%ebx,%3 ; movl %%ebx,%3 ; .endif \n\t" | ||
"cpuid \n\t" | ||
".ifnc %%ebx,%3 ; xchgl %%ebx,%3 ; .endif \n\t" | ||
: "=a" (*a), "=c" (*c), "=d" (*d), EBX_REG (*b) | ||
: "a" (id) | ||
); | ||
} | ||
|
||
void get_flags(void) | ||
{ | ||
u32 max_intel_level, max_amd_level; | ||
u32 tfms; | ||
u32 ignored; | ||
|
||
if (loaded_flags) | ||
return; | ||
loaded_flags = true; | ||
|
||
if (has_fpu()) | ||
set_bit(X86_FEATURE_FPU, cpu.flags); | ||
|
||
if (has_eflag(X86_EFLAGS_ID)) { | ||
cpuid(0x0, &max_intel_level, &cpu_vendor[0], &cpu_vendor[2], | ||
&cpu_vendor[1]); | ||
|
||
if (max_intel_level >= 0x00000001 && | ||
max_intel_level <= 0x0000ffff) { | ||
cpuid(0x1, &tfms, &ignored, &cpu.flags[4], | ||
&cpu.flags[0]); | ||
cpu.level = (tfms >> 8) & 15; | ||
cpu.model = (tfms >> 4) & 15; | ||
if (cpu.level >= 6) | ||
cpu.model += ((tfms >> 16) & 0xf) << 4; | ||
} | ||
|
||
cpuid(0x80000000, &max_amd_level, &ignored, &ignored, | ||
&ignored); | ||
|
||
if (max_amd_level >= 0x80000001 && | ||
max_amd_level <= 0x8000ffff) { | ||
cpuid(0x80000001, &ignored, &ignored, &cpu.flags[6], | ||
&cpu.flags[1]); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
#ifndef BOOT_CPUFLAGS_H | ||
#define BOOT_CPUFLAGS_H | ||
|
||
#include <asm/cpufeature.h> | ||
#include <asm/processor-flags.h> | ||
|
||
struct cpu_features { | ||
int level; /* Family, or 64 for x86-64 */ | ||
int model; | ||
u32 flags[NCAPINTS]; | ||
}; | ||
|
||
extern struct cpu_features cpu; | ||
extern u32 cpu_vendor[3]; | ||
|
||
int has_eflag(unsigned long mask); | ||
void get_flags(void); | ||
|
||
#endif |