blob: b2b7b84ab95b652c29e038f2357509027492598b [file] [log] [blame]
rjw1f884582022-01-06 17:20:42 +08001/*
2* Copyright (c) 2015 Intel Corporation
3*
4* Permission is hereby granted, free of charge, to any person obtaining
5* a copy of this software and associated documentation files
6* (the "Software"), to deal in the Software without restriction,
7* including without limitation the rights to use, copy, modify, merge,
8* publish, distribute, sublicense, and/or sell copies of the Software,
9* and to permit persons to whom the Software is furnished to do so,
10* subject to the following conditions:
11*
12* The above copyright notice and this permission notice shall be
13* included in all copies or substantial portions of the Software.
14*
15* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22*/
23
24#include <arch/x86.h>
25#include <arch/fpu.h>
26#include <kernel/thread.h>
27
28#if X86_WITH_FPU
29
30/* CPUID EAX = 1 return values */
31
32#define ECX_SSE3 (0x00000001 << 0)
33#define ECX_SSSE3 (0x00000001 << 9)
34#define ECX_SSE4_1 (0x00000001 << 19)
35#define ECX_SSE4_2 (0x00000001 << 20)
36#define EDX_FXSR (0x00000001 << 24)
37#define EDX_SSE (0x00000001 << 25)
38#define EDX_SSE2 (0x00000001 << 26)
39#define EDX_FPU (0x00000001 << 0)
40
41#define FPU_CAP(ecx, edx) ((edx & EDX_FPU) != 0)
42
43#define SSE_CAP(ecx, edx) ( \
44 ((ecx & (ECX_SSE3 | ECX_SSSE3 | ECX_SSE4_1 | ECX_SSE4_2)) != 0) || \
45 ((edx & (EDX_SSE | EDX_SSE2)) != 0) \
46 )
47
48#define FXSAVE_CAP(ecx, edx) ((edx & EDX_FXSR) != 0)
49
50static int fp_supported;
51static thread_t *fp_owner;
52
53/* FXSAVE area comprises 512 bytes starting with 16-byte aligned */
54static uint8_t __ALIGNED(16) fpu_init_states[512]={0};
55
56static void get_cpu_cap(uint32_t *ecx, uint32_t *edx)
57{
58 uint32_t eax = 1;
59
60 __asm__ __volatile__
61 ("cpuid" : "=c" (*ecx), "=d" (*edx) : "a" (eax));
62}
63
64void fpu_init(void)
65{
66 uint32_t ecx = 0, edx = 0;
67 uint16_t fcw;
68 uint32_t mxcsr;
69
70#ifdef ARCH_X86_64
71 uint64_t x;
72#else
73 uint32_t x;
74#endif
75
76 fp_supported = 0;
77 fp_owner = NULL;
78
79 get_cpu_cap(&ecx, &edx);
80
81 if (!FPU_CAP(ecx, edx) || !SSE_CAP(ecx, edx) || !FXSAVE_CAP(ecx, edx))
82 return;
83
84 fp_supported = 1;
85
86 /* No x87 emul, monitor co-processor */
87
88 x = x86_get_cr0();
89 x &= ~X86_CR0_EM;
90 x |= X86_CR0_NE;
91 x |= X86_CR0_MP;
92 x86_set_cr0(x);
93
94 /* Init x87 and unmask all exceptions */
95
96 __asm__ __volatile__ ("finit");
97 __asm__ __volatile__("fstcw %0" : "=m" (fcw));
98 fcw &= 0xffc0;
99 __asm__ __volatile__("fldcw %0" : : "m" (fcw));
100
101 /* Init SSE and unmask all exceptions */
102
103 x = x86_get_cr4();
104 x |= X86_CR4_OSXMMEXPT;
105 x |= X86_CR4_OSFXSR;
106 x &= ~X86_CR4_OSXSAVE;
107 x86_set_cr4(x);
108
109 __asm__ __volatile__("stmxcsr %0" : "=m" (mxcsr));
110 mxcsr &= 0x0000003f;
111 __asm__ __volatile__("ldmxcsr %0" : : "m" (mxcsr));
112
113 /* save fpu initial states, and used when new thread creates */
114 __asm__ __volatile__("fxsave %0" : "=m" (fpu_init_states));
115
116 x86_set_cr0(x86_get_cr0() | X86_CR0_TS);
117 return;
118}
119
120void fpu_init_thread_states(thread_t *t)
121{
122 t->arch.fpu_states = (vaddr_t *)ROUNDUP(((vaddr_t)t->arch.fpu_buffer), 16);
123 memcpy(t->arch.fpu_states,fpu_init_states,sizeof(t->arch.fpu_buffer));
124}
125
126void fpu_context_switch(thread_t *old_thread, thread_t *new_thread)
127{
128 if (fp_supported == 0)
129 return;
130
131 if (new_thread != fp_owner)
132 x86_set_cr0(x86_get_cr0() | X86_CR0_TS);
133 else
134 x86_set_cr0(x86_get_cr0() & ~X86_CR0_TS);
135
136 return;
137}
138
139void fpu_dev_na_handler(void)
140{
141 thread_t *self;
142
143 x86_set_cr0(x86_get_cr0() & ~X86_CR0_TS);
144
145 if (fp_supported == 0)
146 return;
147
148 self = get_current_thread();
149
150 if ((fp_owner != NULL) && (fp_owner != self)) {
151 __asm__ __volatile__("fxsave %0" : "=m" (*fp_owner->arch.fpu_states));
152 __asm__ __volatile__("fxrstor %0" : : "m" (*self->arch.fpu_states));
153 }
154
155 fp_owner = self;
156 return;
157}
158#endif
159
160/* End of file */