Statistics
| Branch: | Revision:

root / target-i386 / machine.c @ b0a46a33

History | View | Annotate | Download (9.2 kB)

1
#include "hw/hw.h"
2
#include "hw/boards.h"
3
#include "hw/pc.h"
4
#include "hw/isa.h"
5

    
6
#include "exec-all.h"
7
#include "kvm.h"
8

    
9
static void cpu_put_seg(QEMUFile *f, SegmentCache *dt)
10
{
11
    qemu_put_be32(f, dt->selector);
12
    qemu_put_betl(f, dt->base);
13
    qemu_put_be32(f, dt->limit);
14
    qemu_put_be32(f, dt->flags);
15
}
16

    
17
static void cpu_get_seg(QEMUFile *f, SegmentCache *dt)
18
{
19
    dt->selector = qemu_get_be32(f);
20
    dt->base = qemu_get_betl(f);
21
    dt->limit = qemu_get_be32(f);
22
    dt->flags = qemu_get_be32(f);
23
}
24

    
25
void cpu_save(QEMUFile *f, void *opaque)
26
{
27
    CPUState *env = opaque;
28
    uint16_t fptag, fpus, fpuc, fpregs_format;
29
    uint32_t hflags;
30
    int32_t a20_mask;
31
    int i;
32

    
33
    cpu_synchronize_state(env, 0);
34

    
35
    for(i = 0; i < CPU_NB_REGS; i++)
36
        qemu_put_betls(f, &env->regs[i]);
37
    qemu_put_betls(f, &env->eip);
38
    qemu_put_betls(f, &env->eflags);
39
    hflags = env->hflags; /* XXX: suppress most of the redundant hflags */
40
    qemu_put_be32s(f, &hflags);
41

    
42
    /* FPU */
43
    fpuc = env->fpuc;
44
    fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
45
    fptag = 0;
46
    for(i = 0; i < 8; i++) {
47
        fptag |= ((!env->fptags[i]) << i);
48
    }
49

    
50
    qemu_put_be16s(f, &fpuc);
51
    qemu_put_be16s(f, &fpus);
52
    qemu_put_be16s(f, &fptag);
53

    
54
#ifdef USE_X86LDOUBLE
55
    fpregs_format = 0;
56
#else
57
    fpregs_format = 1;
58
#endif
59
    qemu_put_be16s(f, &fpregs_format);
60

    
61
    for(i = 0; i < 8; i++) {
62
#ifdef USE_X86LDOUBLE
63
        {
64
            uint64_t mant;
65
            uint16_t exp;
66
            /* we save the real CPU data (in case of MMX usage only 'mant'
67
               contains the MMX register */
68
            cpu_get_fp80(&mant, &exp, env->fpregs[i].d);
69
            qemu_put_be64(f, mant);
70
            qemu_put_be16(f, exp);
71
        }
72
#else
73
        /* if we use doubles for float emulation, we save the doubles to
74
           avoid losing information in case of MMX usage. It can give
75
           problems if the image is restored on a CPU where long
76
           doubles are used instead. */
77
        qemu_put_be64(f, env->fpregs[i].mmx.MMX_Q(0));
78
#endif
79
    }
80

    
81
    for(i = 0; i < 6; i++)
82
        cpu_put_seg(f, &env->segs[i]);
83
    cpu_put_seg(f, &env->ldt);
84
    cpu_put_seg(f, &env->tr);
85
    cpu_put_seg(f, &env->gdt);
86
    cpu_put_seg(f, &env->idt);
87

    
88
    qemu_put_be32s(f, &env->sysenter_cs);
89
    qemu_put_betls(f, &env->sysenter_esp);
90
    qemu_put_betls(f, &env->sysenter_eip);
91

    
92
    qemu_put_betls(f, &env->cr[0]);
93
    qemu_put_betls(f, &env->cr[2]);
94
    qemu_put_betls(f, &env->cr[3]);
95
    qemu_put_betls(f, &env->cr[4]);
96

    
97
    for(i = 0; i < 8; i++)
98
        qemu_put_betls(f, &env->dr[i]);
99

    
100
    /* MMU */
101
    a20_mask = (int32_t) env->a20_mask;
102
    qemu_put_sbe32s(f, &a20_mask);
103

    
104
    /* XMM */
105
    qemu_put_be32s(f, &env->mxcsr);
106
    for(i = 0; i < CPU_NB_REGS; i++) {
107
        qemu_put_be64s(f, &env->xmm_regs[i].XMM_Q(0));
108
        qemu_put_be64s(f, &env->xmm_regs[i].XMM_Q(1));
109
    }
110

    
111
#ifdef TARGET_X86_64
112
    qemu_put_be64s(f, &env->efer);
113
    qemu_put_be64s(f, &env->star);
114
    qemu_put_be64s(f, &env->lstar);
115
    qemu_put_be64s(f, &env->cstar);
116
    qemu_put_be64s(f, &env->fmask);
117
    qemu_put_be64s(f, &env->kernelgsbase);
118
#endif
119
    qemu_put_be32s(f, &env->smbase);
120

    
121
    qemu_put_be64s(f, &env->pat);
122
    qemu_put_be32s(f, &env->hflags2);
123
    
124
    qemu_put_be64s(f, &env->vm_hsave);
125
    qemu_put_be64s(f, &env->vm_vmcb);
126
    qemu_put_be64s(f, &env->tsc_offset);
127
    qemu_put_be64s(f, &env->intercept);
128
    qemu_put_be16s(f, &env->intercept_cr_read);
129
    qemu_put_be16s(f, &env->intercept_cr_write);
130
    qemu_put_be16s(f, &env->intercept_dr_read);
131
    qemu_put_be16s(f, &env->intercept_dr_write);
132
    qemu_put_be32s(f, &env->intercept_exceptions);
133
    qemu_put_8s(f, &env->v_tpr);
134

    
135
    /* MTRRs */
136
    for(i = 0; i < 11; i++)
137
        qemu_put_be64s(f, &env->mtrr_fixed[i]);
138
    qemu_put_be64s(f, &env->mtrr_deftype);
139
    for(i = 0; i < 8; i++) {
140
        qemu_put_be64s(f, &env->mtrr_var[i].base);
141
        qemu_put_be64s(f, &env->mtrr_var[i].mask);
142
    }
143
}
144

    
145
#ifdef USE_X86LDOUBLE
146
/* XXX: add that in a FPU generic layer */
147
union x86_longdouble {
148
    uint64_t mant;
149
    uint16_t exp;
150
};
151

    
152
#define MANTD1(fp)        (fp & ((1LL << 52) - 1))
153
#define EXPBIAS1 1023
154
#define EXPD1(fp)        ((fp >> 52) & 0x7FF)
155
#define SIGND1(fp)        ((fp >> 32) & 0x80000000)
156

    
157
static void fp64_to_fp80(union x86_longdouble *p, uint64_t temp)
158
{
159
    int e;
160
    /* mantissa */
161
    p->mant = (MANTD1(temp) << 11) | (1LL << 63);
162
    /* exponent + sign */
163
    e = EXPD1(temp) - EXPBIAS1 + 16383;
164
    e |= SIGND1(temp) >> 16;
165
    p->exp = e;
166
}
167
#endif
168

    
169
int cpu_load(QEMUFile *f, void *opaque, int version_id)
170
{
171
    CPUState *env = opaque;
172
    int i, guess_mmx;
173
    uint32_t hflags;
174
    uint16_t fpus, fpuc, fptag, fpregs_format;
175
    int32_t a20_mask;
176

    
177
    if (version_id != 3 && version_id != 4 && version_id != 5
178
        && version_id != 6 && version_id != 7 && version_id != 8)
179
        return -EINVAL;
180
    for(i = 0; i < CPU_NB_REGS; i++)
181
        qemu_get_betls(f, &env->regs[i]);
182
    qemu_get_betls(f, &env->eip);
183
    qemu_get_betls(f, &env->eflags);
184
    qemu_get_be32s(f, &hflags);
185

    
186
    qemu_get_be16s(f, &fpuc);
187
    qemu_get_be16s(f, &fpus);
188
    qemu_get_be16s(f, &fptag);
189
    qemu_get_be16s(f, &fpregs_format);
190

    
191
    /* NOTE: we cannot always restore the FPU state if the image come
192
       from a host with a different 'USE_X86LDOUBLE' define. We guess
193
       if we are in an MMX state to restore correctly in that case. */
194
    guess_mmx = ((fptag == 0xff) && (fpus & 0x3800) == 0);
195
    for(i = 0; i < 8; i++) {
196
        uint64_t mant;
197
        uint16_t exp;
198

    
199
        switch(fpregs_format) {
200
        case 0:
201
            mant = qemu_get_be64(f);
202
            exp = qemu_get_be16(f);
203
#ifdef USE_X86LDOUBLE
204
            env->fpregs[i].d = cpu_set_fp80(mant, exp);
205
#else
206
            /* difficult case */
207
            if (guess_mmx)
208
                env->fpregs[i].mmx.MMX_Q(0) = mant;
209
            else
210
                env->fpregs[i].d = cpu_set_fp80(mant, exp);
211
#endif
212
            break;
213
        case 1:
214
            mant = qemu_get_be64(f);
215
#ifdef USE_X86LDOUBLE
216
            {
217
                union x86_longdouble *p;
218
                /* difficult case */
219
                p = (void *)&env->fpregs[i];
220
                if (guess_mmx) {
221
                    p->mant = mant;
222
                    p->exp = 0xffff;
223
                } else {
224
                    fp64_to_fp80(p, mant);
225
                }
226
            }
227
#else
228
            env->fpregs[i].mmx.MMX_Q(0) = mant;
229
#endif
230
            break;
231
        default:
232
            return -EINVAL;
233
        }
234
    }
235

    
236
    env->fpuc = fpuc;
237
    /* XXX: restore FPU round state */
238
    env->fpstt = (fpus >> 11) & 7;
239
    env->fpus = fpus & ~0x3800;
240
    fptag ^= 0xff;
241
    for(i = 0; i < 8; i++) {
242
        env->fptags[i] = (fptag >> i) & 1;
243
    }
244

    
245
    for(i = 0; i < 6; i++)
246
        cpu_get_seg(f, &env->segs[i]);
247
    cpu_get_seg(f, &env->ldt);
248
    cpu_get_seg(f, &env->tr);
249
    cpu_get_seg(f, &env->gdt);
250
    cpu_get_seg(f, &env->idt);
251

    
252
    qemu_get_be32s(f, &env->sysenter_cs);
253
    if (version_id >= 7) {
254
        qemu_get_betls(f, &env->sysenter_esp);
255
        qemu_get_betls(f, &env->sysenter_eip);
256
    } else {
257
        env->sysenter_esp = qemu_get_be32(f);
258
        env->sysenter_eip = qemu_get_be32(f);
259
    }
260

    
261
    qemu_get_betls(f, &env->cr[0]);
262
    qemu_get_betls(f, &env->cr[2]);
263
    qemu_get_betls(f, &env->cr[3]);
264
    qemu_get_betls(f, &env->cr[4]);
265

    
266
    for(i = 0; i < 8; i++)
267
        qemu_get_betls(f, &env->dr[i]);
268
    cpu_breakpoint_remove_all(env, BP_CPU);
269
    cpu_watchpoint_remove_all(env, BP_CPU);
270
    for (i = 0; i < 4; i++)
271
        hw_breakpoint_insert(env, i);
272

    
273
    /* MMU */
274
    qemu_get_sbe32s(f, &a20_mask);
275
    env->a20_mask = a20_mask;
276

    
277
    qemu_get_be32s(f, &env->mxcsr);
278
    for(i = 0; i < CPU_NB_REGS; i++) {
279
        qemu_get_be64s(f, &env->xmm_regs[i].XMM_Q(0));
280
        qemu_get_be64s(f, &env->xmm_regs[i].XMM_Q(1));
281
    }
282

    
283
#ifdef TARGET_X86_64
284
    qemu_get_be64s(f, &env->efer);
285
    qemu_get_be64s(f, &env->star);
286
    qemu_get_be64s(f, &env->lstar);
287
    qemu_get_be64s(f, &env->cstar);
288
    qemu_get_be64s(f, &env->fmask);
289
    qemu_get_be64s(f, &env->kernelgsbase);
290
#endif
291
    if (version_id >= 4) {
292
        qemu_get_be32s(f, &env->smbase);
293
    }
294
    if (version_id >= 5) {
295
        qemu_get_be64s(f, &env->pat);
296
        qemu_get_be32s(f, &env->hflags2);
297
        if (version_id < 6)
298
            qemu_get_be32s(f, &env->halted);
299

    
300
        qemu_get_be64s(f, &env->vm_hsave);
301
        qemu_get_be64s(f, &env->vm_vmcb);
302
        qemu_get_be64s(f, &env->tsc_offset);
303
        qemu_get_be64s(f, &env->intercept);
304
        qemu_get_be16s(f, &env->intercept_cr_read);
305
        qemu_get_be16s(f, &env->intercept_cr_write);
306
        qemu_get_be16s(f, &env->intercept_dr_read);
307
        qemu_get_be16s(f, &env->intercept_dr_write);
308
        qemu_get_be32s(f, &env->intercept_exceptions);
309
        qemu_get_8s(f, &env->v_tpr);
310
    }
311

    
312
    if (version_id >= 8) {
313
        /* MTRRs */
314
        for(i = 0; i < 11; i++)
315
            qemu_get_be64s(f, &env->mtrr_fixed[i]);
316
        qemu_get_be64s(f, &env->mtrr_deftype);
317
        for(i = 0; i < 8; i++) {
318
            qemu_get_be64s(f, &env->mtrr_var[i].base);
319
            qemu_get_be64s(f, &env->mtrr_var[i].mask);
320
        }
321
    }
322

    
323
    /* XXX: ensure compatiblity for halted bit ? */
324
    /* XXX: compute redundant hflags bits */
325
    env->hflags = hflags;
326
    tlb_flush(env, 1);
327
    cpu_synchronize_state(env, 1);
328
    return 0;
329
}