Skip to content
Navigation Menu
Toggle navigation
Sign in
In this repository
All GitHub Enterprise
↵
Jump to
↵
No suggested jump to results
In this repository
All GitHub Enterprise
↵
Jump to
↵
In this organization
All GitHub Enterprise
↵
Jump to
↵
In this repository
All GitHub Enterprise
↵
Jump to
↵
Sign in
Reseting focus
You signed in with another tab or window.
Reload
to refresh your session.
You signed out in another tab or window.
Reload
to refresh your session.
You switched accounts on another tab or window.
Reload
to refresh your session.
Dismiss alert
{{ message }}
mariux64
/
linux
Public
Notifications
You must be signed in to change notification settings
Fork
0
Star
0
Code
Issues
2
Pull requests
0
Actions
Projects
0
Wiki
Security
Insights
Additional navigation options
Code
Issues
Pull requests
Actions
Projects
Wiki
Security
Insights
Files
2f51c82
Documentation
arch
alpha
arc
arm
arm64
avr32
blackfin
c6x
cris
frv
h8300
hexagon
ia64
m32r
m68k
metag
microblaze
mips
mn10300
nios2
openrisc
parisc
powerpc
s390
score
sh
sparc
tile
um
unicore32
x86
boot
configs
crypto
entry
ia32
include
kernel
acpi
apic
cpu
fpu
Makefile
bugs.c
core.c
init.c
regset.c
signal.c
xstate.c
kprobes
.gitignore
Makefile
alternative.c
amd_gart_64.c
amd_nb.c
apb_timer.c
aperture_64.c
apm_32.c
asm-offsets.c
asm-offsets_32.c
asm-offsets_64.c
audit_64.c
bootflag.c
check.c
cpuid.c
crash.c
crash_dump_32.c
crash_dump_64.c
devicetree.c
doublefault.c
dumpstack.c
dumpstack_32.c
dumpstack_64.c
e820.c
early-quirks.c
early_printk.c
espfix_64.c
ftrace.c
head.c
head32.c
head64.c
head_32.S
head_64.S
hpet.c
hw_breakpoint.c
i386_ksyms_32.c
i8237.c
i8253.c
i8259.c
io_delay.c
ioport.c
irq.c
irq_32.c
irq_64.c
irq_work.c
irqinit.c
jump_label.c
kdebugfs.c
kexec-bzimage64.c
kgdb.c
ksysfs.c
kvm.c
kvmclock.c
ldt.c
livepatch.c
machine_kexec_32.c
machine_kexec_64.c
mcount_64.S
mmconf-fam10h_64.c
module.c
mpparse.c
msr.c
nmi.c
nmi_selftest.c
paravirt-spinlocks.c
paravirt.c
paravirt_patch_32.c
paravirt_patch_64.c
pci-calgary_64.c
pci-dma.c
pci-iommu_table.c
pci-nommu.c
pci-swiotlb.c
pcspeaker.c
perf_regs.c
pmem.c
probe_roms.c
process.c
process_32.c
process_64.c
ptrace.c
pvclock.c
quirks.c
reboot.c
reboot_fixups_32.c
relocate_kernel_32.S
relocate_kernel_64.S
resource.c
rtc.c
setup.c
setup_percpu.c
signal.c
signal_compat.c
smp.c
smpboot.c
stacktrace.c
step.c
sys_x86_64.c
sysfb.c
sysfb_efi.c
sysfb_simplefb.c
tboot.c
tce_64.c
test_nx.c
test_rodata.c
time.c
tls.c
tls.h
topology.c
trace_clock.c
tracepoint.c
traps.c
tsc.c
tsc_msr.c
tsc_sync.c
uprobes.c
verify_cpu.S
vm86_32.c
vmlinux.lds.S
vsmp_64.c
x8664_ksyms_64.c
x86_init.c
kvm
lguest
lib
math-emu
mm
net
oprofile
pci
platform
power
purgatory
ras
realmode
tools
um
video
xen
.gitignore
Kbuild
Kconfig
Kconfig.cpu
Kconfig.debug
Makefile
Makefile.um
Makefile_32.cpu
xtensa
.gitignore
Kconfig
block
certs
crypto
drivers
firmware
fs
include
init
ipc
kernel
lib
mm
net
samples
scripts
security
sound
tools
usr
virt
.get_maintainer.ignore
.gitignore
.mailmap
COPYING
CREDITS
Kbuild
Kconfig
MAINTAINERS
Makefile
README
REPORTING-BUGS
Breadcrumbs
linux
/
arch
/
x86
/
kernel
/
fpu
/
init.c
Blame
Blame
Latest commit
History
History
406 lines (350 loc) · 11 KB
Breadcrumbs
linux
/
arch
/
x86
/
kernel
/
fpu
/
init.c
Top
File metadata and controls
Code
Blame
406 lines (350 loc) · 11 KB
Raw
/* * x86 FPU boot time init code: */ #include <asm/fpu/internal.h> #include <asm/tlbflush.h> #include <asm/setup.h> #include <asm/cmdline.h> #include <linux/sched.h> #include <linux/init.h> /* * Initialize the TS bit in CR0 according to the style of context-switches * we are using: */ static void fpu__init_cpu_ctx_switch(void) { if (!boot_cpu_has(X86_FEATURE_EAGER_FPU)) stts(); else clts(); } /* * Initialize the registers found in all CPUs, CR0 and CR4: */ static void fpu__init_cpu_generic(void) { unsigned long cr0; unsigned long cr4_mask = 0; if (cpu_has_fxsr) cr4_mask |= X86_CR4_OSFXSR; if (cpu_has_xmm) cr4_mask |= X86_CR4_OSXMMEXCPT; if (cr4_mask) cr4_set_bits(cr4_mask); cr0 = read_cr0(); cr0 &= ~(X86_CR0_TS|X86_CR0_EM); /* clear TS and EM */ if (!cpu_has_fpu) cr0 |= X86_CR0_EM; write_cr0(cr0); /* Flush out any pending x87 state: */ #ifdef CONFIG_MATH_EMULATION if (!cpu_has_fpu) fpstate_init_soft(¤t->thread.fpu.state.soft); else #endif asm volatile ("fninit"); } /* * Enable all supported FPU features. Called when a CPU is brought online: */ void fpu__init_cpu(void) { fpu__init_cpu_generic(); fpu__init_cpu_xstate(); fpu__init_cpu_ctx_switch(); } /* * The earliest FPU detection code. * * Set the X86_FEATURE_FPU CPU-capability bit based on * trying to execute an actual sequence of FPU instructions: */ static void fpu__init_system_early_generic(struct cpuinfo_x86 *c) { unsigned long cr0; u16 fsw, fcw; fsw = fcw = 0xffff; cr0 = read_cr0(); cr0 &= ~(X86_CR0_TS | X86_CR0_EM); write_cr0(cr0); if (!test_bit(X86_FEATURE_FPU, (unsigned long *)cpu_caps_cleared)) { asm volatile("fninit ; fnstsw %0 ; fnstcw %1" : "+m" (fsw), "+m" (fcw)); if (fsw == 0 && (fcw & 0x103f) == 0x003f) set_cpu_cap(c, X86_FEATURE_FPU); else clear_cpu_cap(c, X86_FEATURE_FPU); } #ifndef CONFIG_MATH_EMULATION if (!cpu_has_fpu) { pr_emerg("x86/fpu: Giving up, no FPU found and no math emulation present\n"); for (;;) asm volatile("hlt"); } #endif } /* * Boot time FPU feature detection code: */ unsigned int mxcsr_feature_mask __read_mostly = 0xffffffffu; static void __init fpu__init_system_mxcsr(void) { unsigned int mask = 0; if (cpu_has_fxsr) { /* Static because GCC does not get 16-byte stack alignment right: */ static struct fxregs_state fxregs __initdata; asm volatile("fxsave %0" : "+m" (fxregs)); mask = fxregs.mxcsr_mask; /* * If zero then use the default features mask, * which has all features set, except the * denormals-are-zero feature bit: */ if (mask == 0) mask = 0x0000ffbf; } mxcsr_feature_mask &= mask; } /* * Once per bootup FPU initialization sequences that will run on most x86 CPUs: */ static void __init fpu__init_system_generic(void) { /* * Set up the legacy init FPU context. (xstate init might overwrite this * with a more modern format, if the CPU supports it.) */ fpstate_init(&init_fpstate); fpu__init_system_mxcsr(); } /* * Size of the FPU context state. All tasks in the system use the * same context size, regardless of what portion they use. * This is inherent to the XSAVE architecture which puts all state * components into a single, continuous memory block: */ unsigned int xstate_size; EXPORT_SYMBOL_GPL(xstate_size); /* Get alignment of the TYPE. */ #define TYPE_ALIGN(TYPE) offsetof(struct { char x; TYPE test; }, test) /* * Enforce that 'MEMBER' is the last field of 'TYPE'. * * Align the computed size with alignment of the TYPE, * because that's how C aligns structs. */ #define CHECK_MEMBER_AT_END_OF(TYPE, MEMBER) \ BUILD_BUG_ON(sizeof(TYPE) != ALIGN(offsetofend(TYPE, MEMBER), \ TYPE_ALIGN(TYPE))) /* * We append the 'struct fpu' to the task_struct: */ static void __init fpu__init_task_struct_size(void) { int task_size = sizeof(struct task_struct); /* * Subtract off the static size of the register state. * It potentially has a bunch of padding. */ task_size -= sizeof(((struct task_struct *)0)->thread.fpu.state); /* * Add back the dynamically-calculated register state * size. */ task_size += xstate_size; /* * We dynamically size 'struct fpu', so we require that * it be at the end of 'thread_struct' and that * 'thread_struct' be at the end of 'task_struct'. If * you hit a compile error here, check the structure to * see if something got added to the end. */ CHECK_MEMBER_AT_END_OF(struct fpu, state); CHECK_MEMBER_AT_END_OF(struct thread_struct, fpu); CHECK_MEMBER_AT_END_OF(struct task_struct, thread); arch_task_struct_size = task_size; } /* * Set up the xstate_size based on the legacy FPU context size. * * We set this up first, and later it will be overwritten by * fpu__init_system_xstate() if the CPU knows about xstates. */ static void __init fpu__init_system_xstate_size_legacy(void) { static int on_boot_cpu __initdata = 1; WARN_ON_FPU(!on_boot_cpu); on_boot_cpu = 0; /* * Note that xstate_size might be overwriten later during * fpu__init_system_xstate(). */ if (!cpu_has_fpu) { /* * Disable xsave as we do not support it if i387 * emulation is enabled. */ setup_clear_cpu_cap(X86_FEATURE_XSAVE); setup_clear_cpu_cap(X86_FEATURE_XSAVEOPT); xstate_size = sizeof(struct swregs_state); } else { if (cpu_has_fxsr) xstate_size = sizeof(struct fxregs_state); else xstate_size = sizeof(struct fregs_state); } /* * Quirk: we don't yet handle the XSAVES* instructions * correctly, as we don't correctly convert between * standard and compacted format when interfacing * with user-space - so disable it for now. * * The difference is small: with recent CPUs the * compacted format is only marginally smaller than * the standard FPU state format. * * ( This is easy to backport while we are fixing * XSAVES* support. ) */ setup_clear_cpu_cap(X86_FEATURE_XSAVES); } /* * FPU context switching strategies: * * Against popular belief, we don't do lazy FPU saves, due to the * task migration complications it brings on SMP - we only do * lazy FPU restores. * * 'lazy' is the traditional strategy, which is based on setting * CR0::TS to 1 during context-switch (instead of doing a full * restore of the FPU state), which causes the first FPU instruction * after the context switch (whenever it is executed) to fault - at * which point we lazily restore the FPU state into FPU registers. * * Tasks are of course under no obligation to execute FPU instructions, * so it can easily happen that another context-switch occurs without * a single FPU instruction being executed. If we eventually switch * back to the original task (that still owns the FPU) then we have * not only saved the restores along the way, but we also have the * FPU ready to be used for the original task. * * 'eager' switching is used on modern CPUs, there we switch the FPU * state during every context switch, regardless of whether the task * has used FPU instructions in that time slice or not. This is done * because modern FPU context saving instructions are able to optimize * state saving and restoration in hardware: they can detect both * unused and untouched FPU state and optimize accordingly. * * [ Note that even in 'lazy' mode we might optimize context switches * to use 'eager' restores, if we detect that a task is using the FPU * frequently. See the fpu->counter logic in fpu/internal.h for that. ] */ static enum { AUTO, ENABLE, DISABLE } eagerfpu = AUTO; /* * Find supported xfeatures based on cpu features and command-line input. * This must be called after fpu__init_parse_early_param() is called and * xfeatures_mask is enumerated. */ u64 __init fpu__get_supported_xfeatures_mask(void) { /* Support all xfeatures known to us */ if (eagerfpu != DISABLE) return XCNTXT_MASK; /* Warning of xfeatures being disabled for no eagerfpu mode */ if (xfeatures_mask & XFEATURE_MASK_EAGER) { pr_err("x86/fpu: eagerfpu switching disabled, disabling the following xstate features: 0x%llx.\n", xfeatures_mask & XFEATURE_MASK_EAGER); } /* Return a mask that masks out all features requiring eagerfpu mode */ return ~XFEATURE_MASK_EAGER; } /* * Disable features dependent on eagerfpu. */ static void __init fpu__clear_eager_fpu_features(void) { setup_clear_cpu_cap(X86_FEATURE_MPX); } /* * Pick the FPU context switching strategy: * * When eagerfpu is AUTO or ENABLE, we ensure it is ENABLE if either of * the following is true: * * (1) the cpu has xsaveopt, as it has the optimization and doing eager * FPU switching has a relatively low cost compared to a plain xsave; * (2) the cpu has xsave features (e.g. MPX) that depend on eager FPU * switching. Should the kernel boot with noxsaveopt, we support MPX * with eager FPU switching at a higher cost. */ static void __init fpu__init_system_ctx_switch(void) { static bool on_boot_cpu __initdata = 1; WARN_ON_FPU(!on_boot_cpu); on_boot_cpu = 0; WARN_ON_FPU(current->thread.fpu.fpstate_active); current_thread_info()->status = 0; if (boot_cpu_has(X86_FEATURE_XSAVEOPT) && eagerfpu != DISABLE) eagerfpu = ENABLE; if (xfeatures_mask & XFEATURE_MASK_EAGER) eagerfpu = ENABLE; if (eagerfpu == ENABLE) setup_force_cpu_cap(X86_FEATURE_EAGER_FPU); printk(KERN_INFO "x86/fpu: Using '%s' FPU context switches.\n", eagerfpu == ENABLE ? "eager" : "lazy"); } /* * We parse fpu parameters early because fpu__init_system() is executed * before parse_early_param(). */ static void __init fpu__init_parse_early_param(void) { /* * No need to check "eagerfpu=auto" again, since it is the * initial default. */ if (cmdline_find_option_bool(boot_command_line, "eagerfpu=off")) { eagerfpu = DISABLE; fpu__clear_eager_fpu_features(); } else if (cmdline_find_option_bool(boot_command_line, "eagerfpu=on")) { eagerfpu = ENABLE; } if (cmdline_find_option_bool(boot_command_line, "no387")) setup_clear_cpu_cap(X86_FEATURE_FPU); if (cmdline_find_option_bool(boot_command_line, "nofxsr")) { setup_clear_cpu_cap(X86_FEATURE_FXSR); setup_clear_cpu_cap(X86_FEATURE_FXSR_OPT); setup_clear_cpu_cap(X86_FEATURE_XMM); } if (cmdline_find_option_bool(boot_command_line, "noxsave")) fpu__xstate_clear_all_cpu_caps(); if (cmdline_find_option_bool(boot_command_line, "noxsaveopt")) setup_clear_cpu_cap(X86_FEATURE_XSAVEOPT); if (cmdline_find_option_bool(boot_command_line, "noxsaves")) setup_clear_cpu_cap(X86_FEATURE_XSAVES); } /* * Called on the boot CPU once per system bootup, to set up the initial * FPU state that is later cloned into all processes: */ void __init fpu__init_system(struct cpuinfo_x86 *c) { fpu__init_parse_early_param(); fpu__init_system_early_generic(c); /* * The FPU has to be operational for some of the * later FPU init activities: */ fpu__init_cpu(); /* * But don't leave CR0::TS set yet, as some of the FPU setup * methods depend on being able to execute FPU instructions * that will fault on a set TS, such as the FXSAVE in * fpu__init_system_mxcsr(). */ clts(); fpu__init_system_generic(); fpu__init_system_xstate_size_legacy(); fpu__init_system_xstate(); fpu__init_task_struct_size(); fpu__init_system_ctx_switch(); }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
You can’t perform that action at this time.