diff options
Diffstat (limited to 'arch/x86/boot')
-rw-r--r-- | arch/x86/boot/Makefile | 2 | ||||
-rw-r--r-- | arch/x86/boot/boot.h | 10 | ||||
-rw-r--r-- | arch/x86/boot/compressed/Makefile | 2 | ||||
-rw-r--r-- | arch/x86/boot/compressed/cpuflags.c | 12 | ||||
-rw-r--r-- | arch/x86/boot/cpucheck.c | 86 | ||||
-rw-r--r-- | arch/x86/boot/cpuflags.c | 104 | ||||
-rw-r--r-- | arch/x86/boot/cpuflags.h | 19 |
7 files changed, 138 insertions, 97 deletions
diff --git a/arch/x86/boot/Makefile b/arch/x86/boot/Makefile index 379814bc41e3..0da2e37b37c3 100644 --- a/arch/x86/boot/Makefile +++ b/arch/x86/boot/Makefile | |||
@@ -20,7 +20,7 @@ targets := vmlinux.bin setup.bin setup.elf bzImage | |||
20 | targets += fdimage fdimage144 fdimage288 image.iso mtools.conf | 20 | targets += fdimage fdimage144 fdimage288 image.iso mtools.conf |
21 | subdir- := compressed | 21 | subdir- := compressed |
22 | 22 | ||
23 | setup-y += a20.o bioscall.o cmdline.o copy.o cpu.o cpucheck.o | 23 | setup-y += a20.o bioscall.o cmdline.o copy.o cpu.o cpuflags.o cpucheck.o |
24 | setup-y += early_serial_console.o edd.o header.o main.o mca.o memory.o | 24 | setup-y += early_serial_console.o edd.o header.o main.o mca.o memory.o |
25 | setup-y += pm.o pmjump.o printf.o regs.o string.o tty.o video.o | 25 | setup-y += pm.o pmjump.o printf.o regs.o string.o tty.o video.o |
26 | setup-y += video-mode.o version.o | 26 | setup-y += video-mode.o version.o |
diff --git a/arch/x86/boot/boot.h b/arch/x86/boot/boot.h index ef72baeff484..50f8c5e0f37e 100644 --- a/arch/x86/boot/boot.h +++ b/arch/x86/boot/boot.h | |||
@@ -26,9 +26,8 @@ | |||
26 | #include <asm/boot.h> | 26 | #include <asm/boot.h> |
27 | #include <asm/setup.h> | 27 | #include <asm/setup.h> |
28 | #include "bitops.h" | 28 | #include "bitops.h" |
29 | #include <asm/cpufeature.h> | ||
30 | #include <asm/processor-flags.h> | ||
31 | #include "ctype.h" | 29 | #include "ctype.h" |
30 | #include "cpuflags.h" | ||
32 | 31 | ||
33 | /* Useful macros */ | 32 | /* Useful macros */ |
34 | #define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)])) | 33 | #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) | |||
307 | return __cmdline_find_option_bool(cmd_line_ptr, option); | 306 | return __cmdline_find_option_bool(cmd_line_ptr, option); |
308 | } | 307 | } |
309 | 308 | ||
310 | |||
311 | /* cpu.c, cpucheck.c */ | 309 | /* cpu.c, cpucheck.c */ |
312 | struct cpu_features { | ||
313 | int level; /* Family, or 64 for x86-64 */ | ||
314 | int model; | ||
315 | u32 flags[NCAPINTS]; | ||
316 | }; | ||
317 | extern struct cpu_features cpu; | ||
318 | int check_cpu(int *cpu_level_ptr, int *req_level_ptr, u32 **err_flags_ptr); | 310 | int check_cpu(int *cpu_level_ptr, int *req_level_ptr, u32 **err_flags_ptr); |
319 | int validate_cpu(void); | 311 | int validate_cpu(void); |
320 | 312 | ||
diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile index dcd90df10ab4..3312f1be9fd9 100644 --- a/arch/x86/boot/compressed/Makefile +++ b/arch/x86/boot/compressed/Makefile | |||
@@ -27,7 +27,7 @@ HOST_EXTRACFLAGS += -I$(srctree)/tools/include | |||
27 | 27 | ||
28 | VMLINUX_OBJS = $(obj)/vmlinux.lds $(obj)/head_$(BITS).o $(obj)/misc.o \ | 28 | VMLINUX_OBJS = $(obj)/vmlinux.lds $(obj)/head_$(BITS).o $(obj)/misc.o \ |
29 | $(obj)/string.o $(obj)/cmdline.o $(obj)/early_serial_console.o \ | 29 | $(obj)/string.o $(obj)/cmdline.o $(obj)/early_serial_console.o \ |
30 | $(obj)/piggy.o | 30 | $(obj)/piggy.o $(obj)/cpuflags.o |
31 | 31 | ||
32 | $(obj)/eboot.o: KBUILD_CFLAGS += -fshort-wchar -mno-red-zone | 32 | $(obj)/eboot.o: KBUILD_CFLAGS += -fshort-wchar -mno-red-zone |
33 | 33 | ||
diff --git a/arch/x86/boot/compressed/cpuflags.c b/arch/x86/boot/compressed/cpuflags.c new file mode 100644 index 000000000000..931cba6a4bb0 --- /dev/null +++ b/arch/x86/boot/compressed/cpuflags.c | |||
@@ -0,0 +1,12 @@ | |||
1 | #ifdef CONFIG_RANDOMIZE_BASE | ||
2 | |||
3 | #include "../cpuflags.c" | ||
4 | |||
5 | bool has_cpuflag(int flag) | ||
6 | { | ||
7 | get_flags(); | ||
8 | |||
9 | return test_bit(flag, cpu.flags); | ||
10 | } | ||
11 | |||
12 | #endif | ||
diff --git a/arch/x86/boot/cpucheck.c b/arch/x86/boot/cpucheck.c index 4d3ff037201f..e1f3c166a512 100644 --- a/arch/x86/boot/cpucheck.c +++ b/arch/x86/boot/cpucheck.c | |||
@@ -28,8 +28,6 @@ | |||
28 | #include <asm/required-features.h> | 28 | #include <asm/required-features.h> |
29 | #include <asm/msr-index.h> | 29 | #include <asm/msr-index.h> |
30 | 30 | ||
31 | struct cpu_features cpu; | ||
32 | static u32 cpu_vendor[3]; | ||
33 | static u32 err_flags[NCAPINTS]; | 31 | static u32 err_flags[NCAPINTS]; |
34 | 32 | ||
35 | static const int req_level = CONFIG_X86_MINIMUM_CPU_FAMILY; | 33 | static const int req_level = CONFIG_X86_MINIMUM_CPU_FAMILY; |
@@ -69,90 +67,6 @@ static int is_transmeta(void) | |||
69 | cpu_vendor[2] == A32('M', 'x', '8', '6'); | 67 | cpu_vendor[2] == A32('M', 'x', '8', '6'); |
70 | } | 68 | } |
71 | 69 | ||
72 | static int has_fpu(void) | ||
73 | { | ||
74 | u16 fcw = -1, fsw = -1; | ||
75 | u32 cr0; | ||
76 | |||
77 | asm("movl %%cr0,%0" : "=r" (cr0)); | ||
78 | if (cr0 & (X86_CR0_EM|X86_CR0_TS)) { | ||
79 | cr0 &= ~(X86_CR0_EM|X86_CR0_TS); | ||
80 | asm volatile("movl %0,%%cr0" : : "r" (cr0)); | ||
81 | } | ||
82 | |||
83 | asm volatile("fninit ; fnstsw %0 ; fnstcw %1" | ||
84 | : "+m" (fsw), "+m" (fcw)); | ||
85 | |||
86 | return fsw == 0 && (fcw & 0x103f) == 0x003f; | ||
87 | } | ||
88 | |||
89 | static int has_eflag(u32 mask) | ||
90 | { | ||
91 | u32 f0, f1; | ||
92 | |||
93 | asm("pushfl ; " | ||
94 | "pushfl ; " | ||
95 | "popl %0 ; " | ||
96 | "movl %0,%1 ; " | ||
97 | "xorl %2,%1 ; " | ||
98 | "pushl %1 ; " | ||
99 | "popfl ; " | ||
100 | "pushfl ; " | ||
101 | "popl %1 ; " | ||
102 | "popfl" | ||
103 | : "=&r" (f0), "=&r" (f1) | ||
104 | : "ri" (mask)); | ||
105 | |||
106 | return !!((f0^f1) & mask); | ||
107 | } | ||
108 | |||
109 | static void get_flags(void) | ||
110 | { | ||
111 | u32 max_intel_level, max_amd_level; | ||
112 | u32 tfms; | ||
113 | |||
114 | if (has_fpu()) | ||
115 | set_bit(X86_FEATURE_FPU, cpu.flags); | ||
116 | |||
117 | if (has_eflag(X86_EFLAGS_ID)) { | ||
118 | asm("cpuid" | ||
119 | : "=a" (max_intel_level), | ||
120 | "=b" (cpu_vendor[0]), | ||
121 | "=d" (cpu_vendor[1]), | ||
122 | "=c" (cpu_vendor[2]) | ||
123 | : "a" (0)); | ||
124 | |||
125 | if (max_intel_level >= 0x00000001 && | ||
126 | max_intel_level <= 0x0000ffff) { | ||
127 | asm("cpuid" | ||
128 | : "=a" (tfms), | ||
129 | "=c" (cpu.flags[4]), | ||
130 | "=d" (cpu.flags[0]) | ||
131 | : "a" (0x00000001) | ||
132 | : "ebx"); | ||
133 | cpu.level = (tfms >> 8) & 15; | ||
134 | cpu.model = (tfms >> 4) & 15; | ||
135 | if (cpu.level >= 6) | ||
136 | cpu.model += ((tfms >> 16) & 0xf) << 4; | ||
137 | } | ||
138 | |||
139 | asm("cpuid" | ||
140 | : "=a" (max_amd_level) | ||
141 | : "a" (0x80000000) | ||
142 | : "ebx", "ecx", "edx"); | ||
143 | |||
144 | if (max_amd_level >= 0x80000001 && | ||
145 | max_amd_level <= 0x8000ffff) { | ||
146 | u32 eax = 0x80000001; | ||
147 | asm("cpuid" | ||
148 | : "+a" (eax), | ||
149 | "=c" (cpu.flags[6]), | ||
150 | "=d" (cpu.flags[1]) | ||
151 | : : "ebx"); | ||
152 | } | ||
153 | } | ||
154 | } | ||
155 | |||
156 | /* Returns a bitmask of which words we have error bits in */ | 70 | /* Returns a bitmask of which words we have error bits in */ |
157 | static int check_flags(void) | 71 | static int check_flags(void) |
158 | { | 72 | { |
diff --git a/arch/x86/boot/cpuflags.c b/arch/x86/boot/cpuflags.c new file mode 100644 index 000000000000..b02544a2bce0 --- /dev/null +++ b/arch/x86/boot/cpuflags.c | |||
@@ -0,0 +1,104 @@ | |||
1 | #include <linux/types.h> | ||
2 | #include "bitops.h" | ||
3 | |||
4 | #include <asm/processor-flags.h> | ||
5 | #include <asm/required-features.h> | ||
6 | #include <asm/msr-index.h> | ||
7 | #include "cpuflags.h" | ||
8 | |||
9 | struct cpu_features cpu; | ||
10 | u32 cpu_vendor[3]; | ||
11 | |||
12 | static bool loaded_flags; | ||
13 | |||
14 | static int has_fpu(void) | ||
15 | { | ||
16 | u16 fcw = -1, fsw = -1; | ||
17 | unsigned long cr0; | ||
18 | |||
19 | asm volatile("mov %%cr0,%0" : "=r" (cr0)); | ||
20 | if (cr0 & (X86_CR0_EM|X86_CR0_TS)) { | ||
21 | cr0 &= ~(X86_CR0_EM|X86_CR0_TS); | ||
22 | asm volatile("mov %0,%%cr0" : : "r" (cr0)); | ||
23 | } | ||
24 | |||
25 | asm volatile("fninit ; fnstsw %0 ; fnstcw %1" | ||
26 | : "+m" (fsw), "+m" (fcw)); | ||
27 | |||
28 | return fsw == 0 && (fcw & 0x103f) == 0x003f; | ||
29 | } | ||
30 | |||
31 | int has_eflag(unsigned long mask) | ||
32 | { | ||
33 | unsigned long f0, f1; | ||
34 | |||
35 | asm volatile("pushf \n\t" | ||
36 | "pushf \n\t" | ||
37 | "pop %0 \n\t" | ||
38 | "mov %0,%1 \n\t" | ||
39 | "xor %2,%1 \n\t" | ||
40 | "push %1 \n\t" | ||
41 | "popf \n\t" | ||
42 | "pushf \n\t" | ||
43 | "pop %1 \n\t" | ||
44 | "popf" | ||
45 | : "=&r" (f0), "=&r" (f1) | ||
46 | : "ri" (mask)); | ||
47 | |||
48 | return !!((f0^f1) & mask); | ||
49 | } | ||
50 | |||
51 | /* Handle x86_32 PIC using ebx. */ | ||
52 | #if defined(__i386__) && defined(__PIC__) | ||
53 | # define EBX_REG "=r" | ||
54 | #else | ||
55 | # define EBX_REG "=b" | ||
56 | #endif | ||
57 | |||
58 | static inline void cpuid(u32 id, u32 *a, u32 *b, u32 *c, u32 *d) | ||
59 | { | ||
60 | asm volatile(".ifnc %%ebx,%3 ; movl %%ebx,%3 ; .endif \n\t" | ||
61 | "cpuid \n\t" | ||
62 | ".ifnc %%ebx,%3 ; xchgl %%ebx,%3 ; .endif \n\t" | ||
63 | : "=a" (*a), "=c" (*c), "=d" (*d), EBX_REG (*b) | ||
64 | : "a" (id) | ||
65 | ); | ||
66 | } | ||
67 | |||
68 | void get_flags(void) | ||
69 | { | ||
70 | u32 max_intel_level, max_amd_level; | ||
71 | u32 tfms; | ||
72 | u32 ignored; | ||
73 | |||
74 | if (loaded_flags) | ||
75 | return; | ||
76 | loaded_flags = true; | ||
77 | |||
78 | if (has_fpu()) | ||
79 | set_bit(X86_FEATURE_FPU, cpu.flags); | ||
80 | |||
81 | if (has_eflag(X86_EFLAGS_ID)) { | ||
82 | cpuid(0x0, &max_intel_level, &cpu_vendor[0], &cpu_vendor[2], | ||
83 | &cpu_vendor[1]); | ||
84 | |||
85 | if (max_intel_level >= 0x00000001 && | ||
86 | max_intel_level <= 0x0000ffff) { | ||
87 | cpuid(0x1, &tfms, &ignored, &cpu.flags[4], | ||
88 | &cpu.flags[0]); | ||
89 | cpu.level = (tfms >> 8) & 15; | ||
90 | cpu.model = (tfms >> 4) & 15; | ||
91 | if (cpu.level >= 6) | ||
92 | cpu.model += ((tfms >> 16) & 0xf) << 4; | ||
93 | } | ||
94 | |||
95 | cpuid(0x80000000, &max_amd_level, &ignored, &ignored, | ||
96 | &ignored); | ||
97 | |||
98 | if (max_amd_level >= 0x80000001 && | ||
99 | max_amd_level <= 0x8000ffff) { | ||
100 | cpuid(0x80000001, &ignored, &ignored, &cpu.flags[6], | ||
101 | &cpu.flags[1]); | ||
102 | } | ||
103 | } | ||
104 | } | ||
diff --git a/arch/x86/boot/cpuflags.h b/arch/x86/boot/cpuflags.h new file mode 100644 index 000000000000..9bb4e25f7317 --- /dev/null +++ b/arch/x86/boot/cpuflags.h | |||
@@ -0,0 +1,19 @@ | |||
1 | #ifndef BOOT_CPUFLAGS_H | ||
2 | #define BOOT_CPUFLAGS_H | ||
3 | |||
4 | #include <asm/cpufeature.h> | ||
5 | #include <asm/processor-flags.h> | ||
6 | |||
7 | struct cpu_features { | ||
8 | int level; /* Family, or 64 for x86-64 */ | ||
9 | int model; | ||
10 | u32 flags[NCAPINTS]; | ||
11 | }; | ||
12 | |||
13 | extern struct cpu_features cpu; | ||
14 | extern u32 cpu_vendor[3]; | ||
15 | |||
16 | int has_eflag(unsigned long mask); | ||
17 | void get_flags(void); | ||
18 | |||
19 | #endif | ||