mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-15 00:04:15 +08:00
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>
This commit is contained in:
parent
d751c169e9
commit
dd78b97367
@ -20,7 +20,7 @@ targets := vmlinux.bin setup.bin setup.elf bzImage
|
||||
targets += fdimage fdimage144 fdimage288 image.iso mtools.conf
|
||||
subdir- := compressed
|
||||
|
||||
setup-y += a20.o bioscall.o cmdline.o copy.o cpu.o cpucheck.o
|
||||
setup-y += a20.o bioscall.o cmdline.o copy.o cpu.o cpuflags.o cpucheck.o
|
||||
setup-y += early_serial_console.o edd.o header.o main.o mca.o memory.o
|
||||
setup-y += pm.o pmjump.o printf.o regs.o string.o tty.o video.o
|
||||
setup-y += video-mode.o version.o
|
||||
|
@ -26,9 +26,8 @@
|
||||
#include <asm/boot.h>
|
||||
#include <asm/setup.h>
|
||||
#include "bitops.h"
|
||||
#include <asm/cpufeature.h>
|
||||
#include <asm/processor-flags.h>
|
||||
#include "ctype.h"
|
||||
#include "cpuflags.h"
|
||||
|
||||
/* Useful macros */
|
||||
#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
|
||||
@ -307,14 +306,7 @@ static inline int cmdline_find_option_bool(const char *option)
|
||||
return __cmdline_find_option_bool(cmd_line_ptr, option);
|
||||
}
|
||||
|
||||
|
||||
/* cpu.c, cpucheck.c */
|
||||
struct cpu_features {
|
||||
int level; /* Family, or 64 for x86-64 */
|
||||
int model;
|
||||
u32 flags[NCAPINTS];
|
||||
};
|
||||
extern struct cpu_features cpu;
|
||||
int check_cpu(int *cpu_level_ptr, int *req_level_ptr, u32 **err_flags_ptr);
|
||||
int validate_cpu(void);
|
||||
|
||||
|
@ -27,7 +27,7 @@ HOST_EXTRACFLAGS += -I$(srctree)/tools/include
|
||||
|
||||
VMLINUX_OBJS = $(obj)/vmlinux.lds $(obj)/head_$(BITS).o $(obj)/misc.o \
|
||||
$(obj)/string.o $(obj)/cmdline.o $(obj)/early_serial_console.o \
|
||||
$(obj)/piggy.o
|
||||
$(obj)/piggy.o $(obj)/cpuflags.o
|
||||
|
||||
$(obj)/eboot.o: KBUILD_CFLAGS += -fshort-wchar -mno-red-zone
|
||||
|
||||
|
12
arch/x86/boot/compressed/cpuflags.c
Normal file
12
arch/x86/boot/compressed/cpuflags.c
Normal file
@ -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
|
@ -28,8 +28,6 @@
|
||||
#include <asm/required-features.h>
|
||||
#include <asm/msr-index.h>
|
||||
|
||||
struct cpu_features cpu;
|
||||
static u32 cpu_vendor[3];
|
||||
static u32 err_flags[NCAPINTS];
|
||||
|
||||
static const int req_level = CONFIG_X86_MINIMUM_CPU_FAMILY;
|
||||
@ -69,90 +67,6 @@ static int is_transmeta(void)
|
||||
cpu_vendor[2] == A32('M', 'x', '8', '6');
|
||||
}
|
||||
|
||||
static int has_fpu(void)
|
||||
{
|
||||
u16 fcw = -1, fsw = -1;
|
||||
u32 cr0;
|
||||
|
||||
asm("movl %%cr0,%0" : "=r" (cr0));
|
||||
if (cr0 & (X86_CR0_EM|X86_CR0_TS)) {
|
||||
cr0 &= ~(X86_CR0_EM|X86_CR0_TS);
|
||||
asm volatile("movl %0,%%cr0" : : "r" (cr0));
|
||||
}
|
||||
|
||||
asm volatile("fninit ; fnstsw %0 ; fnstcw %1"
|
||||
: "+m" (fsw), "+m" (fcw));
|
||||
|
||||
return fsw == 0 && (fcw & 0x103f) == 0x003f;
|
||||
}
|
||||
|
||||
static int has_eflag(u32 mask)
|
||||
{
|
||||
u32 f0, f1;
|
||||
|
||||
asm("pushfl ; "
|
||||
"pushfl ; "
|
||||
"popl %0 ; "
|
||||
"movl %0,%1 ; "
|
||||
"xorl %2,%1 ; "
|
||||
"pushl %1 ; "
|
||||
"popfl ; "
|
||||
"pushfl ; "
|
||||
"popl %1 ; "
|
||||
"popfl"
|
||||
: "=&r" (f0), "=&r" (f1)
|
||||
: "ri" (mask));
|
||||
|
||||
return !!((f0^f1) & mask);
|
||||
}
|
||||
|
||||
static void get_flags(void)
|
||||
{
|
||||
u32 max_intel_level, max_amd_level;
|
||||
u32 tfms;
|
||||
|
||||
if (has_fpu())
|
||||
set_bit(X86_FEATURE_FPU, cpu.flags);
|
||||
|
||||
if (has_eflag(X86_EFLAGS_ID)) {
|
||||
asm("cpuid"
|
||||
: "=a" (max_intel_level),
|
||||
"=b" (cpu_vendor[0]),
|
||||
"=d" (cpu_vendor[1]),
|
||||
"=c" (cpu_vendor[2])
|
||||
: "a" (0));
|
||||
|
||||
if (max_intel_level >= 0x00000001 &&
|
||||
max_intel_level <= 0x0000ffff) {
|
||||
asm("cpuid"
|
||||
: "=a" (tfms),
|
||||
"=c" (cpu.flags[4]),
|
||||
"=d" (cpu.flags[0])
|
||||
: "a" (0x00000001)
|
||||
: "ebx");
|
||||
cpu.level = (tfms >> 8) & 15;
|
||||
cpu.model = (tfms >> 4) & 15;
|
||||
if (cpu.level >= 6)
|
||||
cpu.model += ((tfms >> 16) & 0xf) << 4;
|
||||
}
|
||||
|
||||
asm("cpuid"
|
||||
: "=a" (max_amd_level)
|
||||
: "a" (0x80000000)
|
||||
: "ebx", "ecx", "edx");
|
||||
|
||||
if (max_amd_level >= 0x80000001 &&
|
||||
max_amd_level <= 0x8000ffff) {
|
||||
u32 eax = 0x80000001;
|
||||
asm("cpuid"
|
||||
: "+a" (eax),
|
||||
"=c" (cpu.flags[6]),
|
||||
"=d" (cpu.flags[1])
|
||||
: : "ebx");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns a bitmask of which words we have error bits in */
|
||||
static int check_flags(void)
|
||||
{
|
||||
|
104
arch/x86/boot/cpuflags.c
Normal file
104
arch/x86/boot/cpuflags.c
Normal file
@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
19
arch/x86/boot/cpuflags.h
Normal file
19
arch/x86/boot/cpuflags.h
Normal file
@ -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
|
Loading…
Reference in New Issue
Block a user