]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/ia32/fpu-ia32-ux.cpp
342a0a3016b342e559c9dcd3b91571aa57ca3416
[l4.git] / kernel / fiasco / src / kern / ia32 / fpu-ia32-ux.cpp
1 /*
2  * Fiasco FPU Code
3  * Shared between UX and native IA32.
4  */
5
6 INTERFACE[ia32,amd64,ux]:
7
8 EXTENSION class Fpu
9 {
10
11 private:
12   struct fpu_regs       // saved FPU registers
13   {
14     long    cwd;
15     long    swd;
16     long    twd;
17     long    fip;
18     long    fcs;
19     long    foo;
20     long    fos;
21     long    st_space[20];   /* 8*10 bytes for each FP-reg = 80 bytes */
22   };
23
24   struct sse_regs
25   {
26     Unsigned16 cwd;
27     Unsigned16 swd;
28     Unsigned16 twd;
29     Unsigned16 fop;
30     Unsigned32 fip;
31     Unsigned32 fcs;
32     Unsigned32 foo;
33     Unsigned32 fos;
34     Unsigned32 mxcsr;
35     Unsigned32 reserved;
36     Unsigned32 st_space[32];   /*  8*16 bytes for each FP-reg  = 128 bytes */
37     Unsigned32 xmm_space[64];  /* 16*16 bytes for each XMM-reg = 256 bytes */
38     Unsigned32 padding[24];
39   };
40
41   struct Xsave_buffer
42   {
43     sse_regs sse;
44     Unsigned64 header[8];
45   };
46
47   enum Variants
48   {
49     Variant_fpu,
50     Variant_fxsr,
51     Variant_xsave,
52   };
53
54   enum Variants _variant;
55
56   static unsigned _state_size;
57   static unsigned _state_align;
58 };
59
60 IMPLEMENTATION[ia32,amd64,ux]:
61
62 #include <cstring>
63 #include "cpu.h"
64 #include "fpu_state.h"
65 #include "regdefs.h"
66 #include "globals.h"
67 #include "static_assert.h"
68
69 unsigned Fpu::_state_size;
70 unsigned Fpu::_state_align;
71
72 /*
73  * Initialize FPU or SSE state
74  * We don't use finit, because it is slow. Initializing the context in
75  * memory and fetching it via restore_state is supposedly faster
76  */
77 IMPLEMENT inline NEEDS ["cpu.h", "fpu_state.h", "globals.h", "regdefs.h",
78                         "static_assert.h", <cstring>]
79 void
80 Fpu::init_state(Fpu_state *s)
81 {
82   Cpu const &_cpu = Cpu::cpus.cpu(current_cpu());
83   if (_cpu.features() & FEAT_FXSR)
84     {
85       assert (_state_size >= sizeof (sse_regs));
86       sse_regs *sse = reinterpret_cast<sse_regs *>(s->state_buffer());
87
88       memset(sse, 0, sizeof (*sse));
89       sse->cwd = 0x37f;
90
91       if (_cpu.features() & FEAT_SSE)
92         sse->mxcsr = 0x1f80;
93
94       if (_cpu.ext_features() & FEATX_XSAVE)
95         memset(reinterpret_cast<Xsave_buffer *>(s->state_buffer())->header, 0,
96                sizeof (Xsave_buffer::header));
97
98       static_assert(sizeof (sse_regs) == 512, "SSE-regs size not 512 bytes");
99     }
100   else
101     {
102       fpu_regs *fpu = reinterpret_cast<fpu_regs *>(s->state_buffer());
103
104       assert (_state_size >= sizeof (*fpu));
105       memset(fpu, 0, sizeof (*fpu));
106       fpu->cwd = 0xffff037f;
107       fpu->swd = 0xffff0000;
108       fpu->twd = 0xffffffff;
109       fpu->fos = 0xffff0000;
110     }
111 }
112
113 IMPLEMENT
114 void
115 Fpu::init(unsigned cpu)
116 {
117   // Mark FPU busy, so that first FPU operation will yield an exception
118   disable();
119
120   // At first, noone owns the FPU
121   Fpu &f = Fpu::fpu.cpu(cpu);
122
123   f.set_owner(0);
124
125   init_disable();
126
127   printf("FPU%d: %s%s\n", cpu,
128          Cpu::cpus.cpu(cpu).features() & FEAT_SSE  ? "SSE "  : "",
129          Cpu::cpus.cpu(cpu).ext_features() & FEATX_AVX ? "AVX "  : "");
130
131   unsigned cpu_align = 0, cpu_size  = 0;
132
133   if (Cpu::cpus.cpu(cpu).ext_features() & FEATX_XSAVE)
134     {
135       init_xsave(cpu);
136
137       Cpu::cpus.cpu(cpu).update_features_info();
138
139       Unsigned32 eax, ecx, edx;
140       Cpu::cpus.cpu(cpu).cpuid_0xd(0, &eax, &cpu_size, &ecx, &edx);
141       cpu_align = 64;
142       f._variant = Variant_xsave;
143     }
144   else if (Cpu::have_fxsr())
145     {
146       cpu_size  = sizeof(sse_regs);
147       cpu_align = 16;
148       f._variant  = Variant_fxsr;
149     }
150   else
151     {
152       cpu_size  = sizeof(fpu_regs);
153       cpu_align = 4;
154       f._variant  = Variant_fpu;
155     }
156
157   if (cpu_size > _state_size)
158     _state_size = cpu_size;
159   if (cpu_align > _state_align)
160     _state_align = cpu_align;
161 }
162
163
164 /**
165  * Return size of FPU context structure, depending on i387 or SSE
166  * @return size of FPU context structure
167  */
168 IMPLEMENT inline NEEDS ["cpu.h", "regdefs.h"]
169 unsigned
170 Fpu::state_size()
171 {
172   return _state_size;
173 }
174
175 /**
176  * Return recommended FPU context alignment, depending on i387 or SSE
177  * @return recommended FPU context alignment
178  */
179 IMPLEMENT inline NEEDS ["cpu.h", "regdefs.h"]
180 unsigned
181 Fpu::state_align()
182 {
183   return _state_align;
184 }