root / target-i386 / machine.c @ cb63669a
History | View | Annotate | Download (7 kB)
1 | 8dd3dca3 | aurel32 | #include "hw/hw.h" |
---|---|---|---|
2 | 8dd3dca3 | aurel32 | #include "hw/boards.h" |
3 | 8dd3dca3 | aurel32 | #include "hw/pc.h" |
4 | 8dd3dca3 | aurel32 | #include "hw/isa.h" |
5 | 8dd3dca3 | aurel32 | |
6 | 8dd3dca3 | aurel32 | #include "exec-all.h" |
7 | 8dd3dca3 | aurel32 | |
8 | 8dd3dca3 | aurel32 | void register_machines(void) |
9 | 8dd3dca3 | aurel32 | { |
10 | 8dd3dca3 | aurel32 | qemu_register_machine(&pc_machine); |
11 | 8dd3dca3 | aurel32 | qemu_register_machine(&isapc_machine); |
12 | 8dd3dca3 | aurel32 | } |
13 | 8dd3dca3 | aurel32 | |
14 | 8dd3dca3 | aurel32 | static void cpu_put_seg(QEMUFile *f, SegmentCache *dt) |
15 | 8dd3dca3 | aurel32 | { |
16 | 8dd3dca3 | aurel32 | qemu_put_be32(f, dt->selector); |
17 | 8dd3dca3 | aurel32 | qemu_put_betl(f, dt->base); |
18 | 8dd3dca3 | aurel32 | qemu_put_be32(f, dt->limit); |
19 | 8dd3dca3 | aurel32 | qemu_put_be32(f, dt->flags); |
20 | 8dd3dca3 | aurel32 | } |
21 | 8dd3dca3 | aurel32 | |
22 | 8dd3dca3 | aurel32 | static void cpu_get_seg(QEMUFile *f, SegmentCache *dt) |
23 | 8dd3dca3 | aurel32 | { |
24 | 8dd3dca3 | aurel32 | dt->selector = qemu_get_be32(f); |
25 | 8dd3dca3 | aurel32 | dt->base = qemu_get_betl(f); |
26 | 8dd3dca3 | aurel32 | dt->limit = qemu_get_be32(f); |
27 | 8dd3dca3 | aurel32 | dt->flags = qemu_get_be32(f); |
28 | 8dd3dca3 | aurel32 | } |
29 | 8dd3dca3 | aurel32 | |
30 | 8dd3dca3 | aurel32 | void cpu_save(QEMUFile *f, void *opaque) |
31 | 8dd3dca3 | aurel32 | { |
32 | 8dd3dca3 | aurel32 | CPUState *env = opaque; |
33 | 8dd3dca3 | aurel32 | uint16_t fptag, fpus, fpuc, fpregs_format; |
34 | 8dd3dca3 | aurel32 | uint32_t hflags; |
35 | 7caa33f7 | aurel32 | int32_t a20_mask; |
36 | 8dd3dca3 | aurel32 | int i;
|
37 | 8dd3dca3 | aurel32 | |
38 | 8dd3dca3 | aurel32 | for(i = 0; i < CPU_NB_REGS; i++) |
39 | 8dd3dca3 | aurel32 | qemu_put_betls(f, &env->regs[i]); |
40 | 8dd3dca3 | aurel32 | qemu_put_betls(f, &env->eip); |
41 | 8dd3dca3 | aurel32 | qemu_put_betls(f, &env->eflags); |
42 | 8dd3dca3 | aurel32 | hflags = env->hflags; /* XXX: suppress most of the redundant hflags */
|
43 | 8dd3dca3 | aurel32 | qemu_put_be32s(f, &hflags); |
44 | 8dd3dca3 | aurel32 | |
45 | 8dd3dca3 | aurel32 | /* FPU */
|
46 | 8dd3dca3 | aurel32 | fpuc = env->fpuc; |
47 | 8dd3dca3 | aurel32 | fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; |
48 | 8dd3dca3 | aurel32 | fptag = 0;
|
49 | 8dd3dca3 | aurel32 | for(i = 0; i < 8; i++) { |
50 | 8dd3dca3 | aurel32 | fptag |= ((!env->fptags[i]) << i); |
51 | 8dd3dca3 | aurel32 | } |
52 | 8dd3dca3 | aurel32 | |
53 | 8dd3dca3 | aurel32 | qemu_put_be16s(f, &fpuc); |
54 | 8dd3dca3 | aurel32 | qemu_put_be16s(f, &fpus); |
55 | 8dd3dca3 | aurel32 | qemu_put_be16s(f, &fptag); |
56 | 8dd3dca3 | aurel32 | |
57 | 8dd3dca3 | aurel32 | #ifdef USE_X86LDOUBLE
|
58 | 8dd3dca3 | aurel32 | fpregs_format = 0;
|
59 | 8dd3dca3 | aurel32 | #else
|
60 | 8dd3dca3 | aurel32 | fpregs_format = 1;
|
61 | 8dd3dca3 | aurel32 | #endif
|
62 | 8dd3dca3 | aurel32 | qemu_put_be16s(f, &fpregs_format); |
63 | 8dd3dca3 | aurel32 | |
64 | 8dd3dca3 | aurel32 | for(i = 0; i < 8; i++) { |
65 | 8dd3dca3 | aurel32 | #ifdef USE_X86LDOUBLE
|
66 | 8dd3dca3 | aurel32 | { |
67 | 8dd3dca3 | aurel32 | uint64_t mant; |
68 | 8dd3dca3 | aurel32 | uint16_t exp; |
69 | 8dd3dca3 | aurel32 | /* we save the real CPU data (in case of MMX usage only 'mant'
|
70 | 8dd3dca3 | aurel32 | contains the MMX register */
|
71 | 8dd3dca3 | aurel32 | cpu_get_fp80(&mant, &exp, env->fpregs[i].d); |
72 | 8dd3dca3 | aurel32 | qemu_put_be64(f, mant); |
73 | 8dd3dca3 | aurel32 | qemu_put_be16(f, exp); |
74 | 8dd3dca3 | aurel32 | } |
75 | 8dd3dca3 | aurel32 | #else
|
76 | 8dd3dca3 | aurel32 | /* if we use doubles for float emulation, we save the doubles to
|
77 | 8dd3dca3 | aurel32 | avoid losing information in case of MMX usage. It can give
|
78 | 8dd3dca3 | aurel32 | problems if the image is restored on a CPU where long
|
79 | 8dd3dca3 | aurel32 | doubles are used instead. */
|
80 | 8dd3dca3 | aurel32 | qemu_put_be64(f, env->fpregs[i].mmx.MMX_Q(0));
|
81 | 8dd3dca3 | aurel32 | #endif
|
82 | 8dd3dca3 | aurel32 | } |
83 | 8dd3dca3 | aurel32 | |
84 | 8dd3dca3 | aurel32 | for(i = 0; i < 6; i++) |
85 | 8dd3dca3 | aurel32 | cpu_put_seg(f, &env->segs[i]); |
86 | 8dd3dca3 | aurel32 | cpu_put_seg(f, &env->ldt); |
87 | 8dd3dca3 | aurel32 | cpu_put_seg(f, &env->tr); |
88 | 8dd3dca3 | aurel32 | cpu_put_seg(f, &env->gdt); |
89 | 8dd3dca3 | aurel32 | cpu_put_seg(f, &env->idt); |
90 | 8dd3dca3 | aurel32 | |
91 | 8dd3dca3 | aurel32 | qemu_put_be32s(f, &env->sysenter_cs); |
92 | 8dd3dca3 | aurel32 | qemu_put_be32s(f, &env->sysenter_esp); |
93 | 8dd3dca3 | aurel32 | qemu_put_be32s(f, &env->sysenter_eip); |
94 | 8dd3dca3 | aurel32 | |
95 | 8dd3dca3 | aurel32 | qemu_put_betls(f, &env->cr[0]);
|
96 | 8dd3dca3 | aurel32 | qemu_put_betls(f, &env->cr[2]);
|
97 | 8dd3dca3 | aurel32 | qemu_put_betls(f, &env->cr[3]);
|
98 | 8dd3dca3 | aurel32 | qemu_put_betls(f, &env->cr[4]);
|
99 | 8dd3dca3 | aurel32 | |
100 | 8dd3dca3 | aurel32 | for(i = 0; i < 8; i++) |
101 | 8dd3dca3 | aurel32 | qemu_put_betls(f, &env->dr[i]); |
102 | 8dd3dca3 | aurel32 | |
103 | 8dd3dca3 | aurel32 | /* MMU */
|
104 | 7caa33f7 | aurel32 | a20_mask = (int32_t) env->a20_mask; |
105 | 7caa33f7 | aurel32 | qemu_put_be32s(f, &a20_mask); |
106 | 8dd3dca3 | aurel32 | |
107 | 8dd3dca3 | aurel32 | /* XMM */
|
108 | 8dd3dca3 | aurel32 | qemu_put_be32s(f, &env->mxcsr); |
109 | 8dd3dca3 | aurel32 | for(i = 0; i < CPU_NB_REGS; i++) { |
110 | 8dd3dca3 | aurel32 | qemu_put_be64s(f, &env->xmm_regs[i].XMM_Q(0));
|
111 | 8dd3dca3 | aurel32 | qemu_put_be64s(f, &env->xmm_regs[i].XMM_Q(1));
|
112 | 8dd3dca3 | aurel32 | } |
113 | 8dd3dca3 | aurel32 | |
114 | 8dd3dca3 | aurel32 | #ifdef TARGET_X86_64
|
115 | 8dd3dca3 | aurel32 | qemu_put_be64s(f, &env->efer); |
116 | 8dd3dca3 | aurel32 | qemu_put_be64s(f, &env->star); |
117 | 8dd3dca3 | aurel32 | qemu_put_be64s(f, &env->lstar); |
118 | 8dd3dca3 | aurel32 | qemu_put_be64s(f, &env->cstar); |
119 | 8dd3dca3 | aurel32 | qemu_put_be64s(f, &env->fmask); |
120 | 8dd3dca3 | aurel32 | qemu_put_be64s(f, &env->kernelgsbase); |
121 | 8dd3dca3 | aurel32 | #endif
|
122 | 8dd3dca3 | aurel32 | qemu_put_be32s(f, &env->smbase); |
123 | 8dd3dca3 | aurel32 | } |
124 | 8dd3dca3 | aurel32 | |
125 | 8dd3dca3 | aurel32 | #ifdef USE_X86LDOUBLE
|
126 | 8dd3dca3 | aurel32 | /* XXX: add that in a FPU generic layer */
|
127 | 8dd3dca3 | aurel32 | union x86_longdouble {
|
128 | 8dd3dca3 | aurel32 | uint64_t mant; |
129 | 8dd3dca3 | aurel32 | uint16_t exp; |
130 | 8dd3dca3 | aurel32 | }; |
131 | 8dd3dca3 | aurel32 | |
132 | 8dd3dca3 | aurel32 | #define MANTD1(fp) (fp & ((1LL << 52) - 1)) |
133 | 8dd3dca3 | aurel32 | #define EXPBIAS1 1023 |
134 | 8dd3dca3 | aurel32 | #define EXPD1(fp) ((fp >> 52) & 0x7FF) |
135 | 8dd3dca3 | aurel32 | #define SIGND1(fp) ((fp >> 32) & 0x80000000) |
136 | 8dd3dca3 | aurel32 | |
137 | 8dd3dca3 | aurel32 | static void fp64_to_fp80(union x86_longdouble *p, uint64_t temp) |
138 | 8dd3dca3 | aurel32 | { |
139 | 8dd3dca3 | aurel32 | int e;
|
140 | 8dd3dca3 | aurel32 | /* mantissa */
|
141 | 8dd3dca3 | aurel32 | p->mant = (MANTD1(temp) << 11) | (1LL << 63); |
142 | 8dd3dca3 | aurel32 | /* exponent + sign */
|
143 | 8dd3dca3 | aurel32 | e = EXPD1(temp) - EXPBIAS1 + 16383;
|
144 | 8dd3dca3 | aurel32 | e |= SIGND1(temp) >> 16;
|
145 | 8dd3dca3 | aurel32 | p->exp = e; |
146 | 8dd3dca3 | aurel32 | } |
147 | 8dd3dca3 | aurel32 | #endif
|
148 | 8dd3dca3 | aurel32 | |
149 | 8dd3dca3 | aurel32 | int cpu_load(QEMUFile *f, void *opaque, int version_id) |
150 | 8dd3dca3 | aurel32 | { |
151 | 8dd3dca3 | aurel32 | CPUState *env = opaque; |
152 | 8dd3dca3 | aurel32 | int i, guess_mmx;
|
153 | 8dd3dca3 | aurel32 | uint32_t hflags; |
154 | 8dd3dca3 | aurel32 | uint16_t fpus, fpuc, fptag, fpregs_format; |
155 | 7caa33f7 | aurel32 | int32_t a20_mask; |
156 | 8dd3dca3 | aurel32 | |
157 | 8dd3dca3 | aurel32 | if (version_id != 3 && version_id != 4) |
158 | 8dd3dca3 | aurel32 | return -EINVAL;
|
159 | 8dd3dca3 | aurel32 | for(i = 0; i < CPU_NB_REGS; i++) |
160 | 8dd3dca3 | aurel32 | qemu_get_betls(f, &env->regs[i]); |
161 | 8dd3dca3 | aurel32 | qemu_get_betls(f, &env->eip); |
162 | 8dd3dca3 | aurel32 | qemu_get_betls(f, &env->eflags); |
163 | 8dd3dca3 | aurel32 | qemu_get_be32s(f, &hflags); |
164 | 8dd3dca3 | aurel32 | |
165 | 8dd3dca3 | aurel32 | qemu_get_be16s(f, &fpuc); |
166 | 8dd3dca3 | aurel32 | qemu_get_be16s(f, &fpus); |
167 | 8dd3dca3 | aurel32 | qemu_get_be16s(f, &fptag); |
168 | 8dd3dca3 | aurel32 | qemu_get_be16s(f, &fpregs_format); |
169 | 8dd3dca3 | aurel32 | |
170 | 8dd3dca3 | aurel32 | /* NOTE: we cannot always restore the FPU state if the image come
|
171 | 8dd3dca3 | aurel32 | from a host with a different 'USE_X86LDOUBLE' define. We guess
|
172 | 8dd3dca3 | aurel32 | if we are in an MMX state to restore correctly in that case. */
|
173 | 8dd3dca3 | aurel32 | guess_mmx = ((fptag == 0xff) && (fpus & 0x3800) == 0); |
174 | 8dd3dca3 | aurel32 | for(i = 0; i < 8; i++) { |
175 | 8dd3dca3 | aurel32 | uint64_t mant; |
176 | 8dd3dca3 | aurel32 | uint16_t exp; |
177 | 8dd3dca3 | aurel32 | |
178 | 8dd3dca3 | aurel32 | switch(fpregs_format) {
|
179 | 8dd3dca3 | aurel32 | case 0: |
180 | 8dd3dca3 | aurel32 | mant = qemu_get_be64(f); |
181 | 8dd3dca3 | aurel32 | exp = qemu_get_be16(f); |
182 | 8dd3dca3 | aurel32 | #ifdef USE_X86LDOUBLE
|
183 | 8dd3dca3 | aurel32 | env->fpregs[i].d = cpu_set_fp80(mant, exp); |
184 | 8dd3dca3 | aurel32 | #else
|
185 | 8dd3dca3 | aurel32 | /* difficult case */
|
186 | 8dd3dca3 | aurel32 | if (guess_mmx)
|
187 | 8dd3dca3 | aurel32 | env->fpregs[i].mmx.MMX_Q(0) = mant;
|
188 | 8dd3dca3 | aurel32 | else
|
189 | 8dd3dca3 | aurel32 | env->fpregs[i].d = cpu_set_fp80(mant, exp); |
190 | 8dd3dca3 | aurel32 | #endif
|
191 | 8dd3dca3 | aurel32 | break;
|
192 | 8dd3dca3 | aurel32 | case 1: |
193 | 8dd3dca3 | aurel32 | mant = qemu_get_be64(f); |
194 | 8dd3dca3 | aurel32 | #ifdef USE_X86LDOUBLE
|
195 | 8dd3dca3 | aurel32 | { |
196 | 8dd3dca3 | aurel32 | union x86_longdouble *p;
|
197 | 8dd3dca3 | aurel32 | /* difficult case */
|
198 | 8dd3dca3 | aurel32 | p = (void *)&env->fpregs[i];
|
199 | 8dd3dca3 | aurel32 | if (guess_mmx) {
|
200 | 8dd3dca3 | aurel32 | p->mant = mant; |
201 | 8dd3dca3 | aurel32 | p->exp = 0xffff;
|
202 | 8dd3dca3 | aurel32 | } else {
|
203 | 8dd3dca3 | aurel32 | fp64_to_fp80(p, mant); |
204 | 8dd3dca3 | aurel32 | } |
205 | 8dd3dca3 | aurel32 | } |
206 | 8dd3dca3 | aurel32 | #else
|
207 | 8dd3dca3 | aurel32 | env->fpregs[i].mmx.MMX_Q(0) = mant;
|
208 | 8dd3dca3 | aurel32 | #endif
|
209 | 8dd3dca3 | aurel32 | break;
|
210 | 8dd3dca3 | aurel32 | default:
|
211 | 8dd3dca3 | aurel32 | return -EINVAL;
|
212 | 8dd3dca3 | aurel32 | } |
213 | 8dd3dca3 | aurel32 | } |
214 | 8dd3dca3 | aurel32 | |
215 | 8dd3dca3 | aurel32 | env->fpuc = fpuc; |
216 | 8dd3dca3 | aurel32 | /* XXX: restore FPU round state */
|
217 | 8dd3dca3 | aurel32 | env->fpstt = (fpus >> 11) & 7; |
218 | 8dd3dca3 | aurel32 | env->fpus = fpus & ~0x3800;
|
219 | 8dd3dca3 | aurel32 | fptag ^= 0xff;
|
220 | 8dd3dca3 | aurel32 | for(i = 0; i < 8; i++) { |
221 | 8dd3dca3 | aurel32 | env->fptags[i] = (fptag >> i) & 1;
|
222 | 8dd3dca3 | aurel32 | } |
223 | 8dd3dca3 | aurel32 | |
224 | 8dd3dca3 | aurel32 | for(i = 0; i < 6; i++) |
225 | 8dd3dca3 | aurel32 | cpu_get_seg(f, &env->segs[i]); |
226 | 8dd3dca3 | aurel32 | cpu_get_seg(f, &env->ldt); |
227 | 8dd3dca3 | aurel32 | cpu_get_seg(f, &env->tr); |
228 | 8dd3dca3 | aurel32 | cpu_get_seg(f, &env->gdt); |
229 | 8dd3dca3 | aurel32 | cpu_get_seg(f, &env->idt); |
230 | 8dd3dca3 | aurel32 | |
231 | 8dd3dca3 | aurel32 | qemu_get_be32s(f, &env->sysenter_cs); |
232 | 8dd3dca3 | aurel32 | qemu_get_be32s(f, &env->sysenter_esp); |
233 | 8dd3dca3 | aurel32 | qemu_get_be32s(f, &env->sysenter_eip); |
234 | 8dd3dca3 | aurel32 | |
235 | 8dd3dca3 | aurel32 | qemu_get_betls(f, &env->cr[0]);
|
236 | 8dd3dca3 | aurel32 | qemu_get_betls(f, &env->cr[2]);
|
237 | 8dd3dca3 | aurel32 | qemu_get_betls(f, &env->cr[3]);
|
238 | 8dd3dca3 | aurel32 | qemu_get_betls(f, &env->cr[4]);
|
239 | 8dd3dca3 | aurel32 | |
240 | 8dd3dca3 | aurel32 | for(i = 0; i < 8; i++) |
241 | 8dd3dca3 | aurel32 | qemu_get_betls(f, &env->dr[i]); |
242 | 8dd3dca3 | aurel32 | |
243 | 8dd3dca3 | aurel32 | /* MMU */
|
244 | 7caa33f7 | aurel32 | qemu_get_be32s(f, &a20_mask); |
245 | 7caa33f7 | aurel32 | env->a20_mask = a20_mask; |
246 | 8dd3dca3 | aurel32 | |
247 | 8dd3dca3 | aurel32 | qemu_get_be32s(f, &env->mxcsr); |
248 | 8dd3dca3 | aurel32 | for(i = 0; i < CPU_NB_REGS; i++) { |
249 | 8dd3dca3 | aurel32 | qemu_get_be64s(f, &env->xmm_regs[i].XMM_Q(0));
|
250 | 8dd3dca3 | aurel32 | qemu_get_be64s(f, &env->xmm_regs[i].XMM_Q(1));
|
251 | 8dd3dca3 | aurel32 | } |
252 | 8dd3dca3 | aurel32 | |
253 | 8dd3dca3 | aurel32 | #ifdef TARGET_X86_64
|
254 | 8dd3dca3 | aurel32 | qemu_get_be64s(f, &env->efer); |
255 | 8dd3dca3 | aurel32 | qemu_get_be64s(f, &env->star); |
256 | 8dd3dca3 | aurel32 | qemu_get_be64s(f, &env->lstar); |
257 | 8dd3dca3 | aurel32 | qemu_get_be64s(f, &env->cstar); |
258 | 8dd3dca3 | aurel32 | qemu_get_be64s(f, &env->fmask); |
259 | 8dd3dca3 | aurel32 | qemu_get_be64s(f, &env->kernelgsbase); |
260 | 8dd3dca3 | aurel32 | #endif
|
261 | 8dd3dca3 | aurel32 | if (version_id >= 4) |
262 | 8dd3dca3 | aurel32 | qemu_get_be32s(f, &env->smbase); |
263 | 8dd3dca3 | aurel32 | |
264 | 8dd3dca3 | aurel32 | /* XXX: compute hflags from scratch, except for CPL and IIF */
|
265 | 8dd3dca3 | aurel32 | env->hflags = hflags; |
266 | 8dd3dca3 | aurel32 | tlb_flush(env, 1);
|
267 | 8dd3dca3 | aurel32 | return 0; |
268 | 8dd3dca3 | aurel32 | } |