]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/ia32/fpu-ia32-ux.cpp
update
[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   set_owner(cpu, 0);
122
123   init_disable();
124
125   printf("FPU%d: %s%s\n", cpu,
126          Cpu::cpus.cpu(cpu).features() & FEAT_SSE  ? "SSE "  : "",
127          Cpu::cpus.cpu(cpu).ext_features() & FEATX_AVX ? "AVX "  : "");
128
129   unsigned cpu_align = 0, cpu_size  = 0;
130
131   if (Cpu::cpus.cpu(cpu).ext_features() & FEATX_XSAVE)
132     {
133       init_xsave(cpu);
134
135       Cpu::cpus.cpu(cpu).update_features_info();
136
137       Unsigned32 eax, ecx, edx;
138       Cpu::cpus.cpu(cpu).cpuid_0xd(0, &eax, &cpu_size, &ecx, &edx);
139       cpu_align = 64;
140       fpu(cpu)._variant = Variant_xsave;
141     }
142   else if (Cpu::have_fxsr())
143     {
144       cpu_size  = sizeof(sse_regs);
145       cpu_align = 16;
146       fpu(cpu)._variant  = Variant_fxsr;
147     }
148   else
149     {
150       cpu_size  = sizeof(fpu_regs);
151       cpu_align = 4;
152       fpu(cpu)._variant  = Variant_fpu;
153     }
154
155   if (cpu_size > _state_size)
156     _state_size = cpu_size;
157   if (cpu_align > _state_align)
158     _state_align = cpu_align;
159 }
160
161
162 /**
163  * Return size of FPU context structure, depending on i387 or SSE
164  * @return size of FPU context structure
165  */
166 IMPLEMENT inline NEEDS ["cpu.h", "regdefs.h"]
167 unsigned
168 Fpu::state_size()
169 {
170   return _state_size;
171 }
172
173 /**
174  * Return recommended FPU context alignment, depending on i387 or SSE
175  * @return recommended FPU context alignment
176  */
177 IMPLEMENT inline NEEDS ["cpu.h", "regdefs.h"]
178 unsigned
179 Fpu::state_align()
180 {
181   return _state_align;
182 }