Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/x86/boot/cpuflags.c
26424 views
1
// SPDX-License-Identifier: GPL-2.0
2
#include <linux/types.h>
3
#include "bitops.h"
4
5
#include <asm/processor-flags.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
#ifdef CONFIG_X86_32
32
/*
33
* For building the 16-bit code we want to explicitly specify 32-bit
34
* push/pop operations, rather than just saying 'pushf' or 'popf' and
35
* letting the compiler choose.
36
*/
37
bool has_eflag(unsigned long mask)
38
{
39
unsigned long f0, f1;
40
41
asm volatile("pushfl \n\t"
42
"pushfl \n\t"
43
"pop %0 \n\t"
44
"mov %0,%1 \n\t"
45
"xor %2,%1 \n\t"
46
"push %1 \n\t"
47
"popfl \n\t"
48
"pushfl \n\t"
49
"pop %1 \n\t"
50
"popfl"
51
: "=&r" (f0), "=&r" (f1)
52
: "ri" (mask));
53
54
return !!((f0^f1) & mask);
55
}
56
#endif
57
58
void cpuid_count(u32 id, u32 count, u32 *a, u32 *b, u32 *c, u32 *d)
59
{
60
asm volatile("cpuid"
61
: "=a" (*a), "=b" (*b), "=c" (*c), "=d" (*d)
62
: "0" (id), "2" (count)
63
);
64
}
65
66
#define cpuid(id, a, b, c, d) cpuid_count(id, 0, a, b, c, d)
67
68
void get_cpuflags(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.family = cpu.level;
91
cpu.model = (tfms >> 4) & 15;
92
if (cpu.level >= 6)
93
cpu.model += ((tfms >> 16) & 0xf) << 4;
94
}
95
96
if (max_intel_level >= 0x00000007) {
97
cpuid_count(0x00000007, 0, &ignored, &ignored,
98
&cpu.flags[16], &ignored);
99
}
100
101
cpuid(0x80000000, &max_amd_level, &ignored, &ignored,
102
&ignored);
103
104
if (max_amd_level >= 0x80000001 &&
105
max_amd_level <= 0x8000ffff) {
106
cpuid(0x80000001, &ignored, &ignored, &cpu.flags[6],
107
&cpu.flags[1]);
108
}
109
110
if (max_amd_level >= 0x8000001f) {
111
u32 ebx;
112
113
/*
114
* The X86_FEATURE_COHERENCY_SFW_NO feature bit is in
115
* the virtualization flags entry (word 8) and set by
116
* scattered.c, so the bit needs to be explicitly set.
117
*/
118
cpuid(0x8000001f, &ignored, &ebx, &ignored, &ignored);
119
if (ebx & BIT(31))
120
set_bit(X86_FEATURE_COHERENCY_SFW_NO, cpu.flags);
121
}
122
}
123
}
124
125