Statistics
| Branch: | Revision:

root / target-i386 / machine.c @ dc1ded53

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

    
8
void register_machines(void)
9
{
10
    qemu_register_machine(&pc_machine);
11
    qemu_register_machine(&isapc_machine);
12
}
13

    
14
static void cpu_put_seg(QEMUFile *f, SegmentCache *dt)
15
{
16
    qemu_put_be32(f, dt->selector);
17
    qemu_put_betl(f, dt->base);
18
    qemu_put_be32(f, dt->limit);
19
    qemu_put_be32(f, dt->flags);
20
}
21

    
22
static void cpu_get_seg(QEMUFile *f, SegmentCache *dt)
23
{
24
    dt->selector = qemu_get_be32(f);
25
    dt->base = qemu_get_betl(f);
26
    dt->limit = qemu_get_be32(f);
27
    dt->flags = qemu_get_be32(f);
28
}
29

    
30
void cpu_save(QEMUFile *f, void *opaque)
31
{
32
    CPUState *env = opaque;
33
    uint16_t fptag, fpus, fpuc, fpregs_format;
34
    uint32_t hflags;
35
    int32_t a20_mask;
36
    int i;
37

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

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

    
53
    qemu_put_be16s(f, &fpuc);
54
    qemu_put_be16s(f, &fpus);
55
    qemu_put_be16s(f, &fptag);
56

    
57
#ifdef USE_X86LDOUBLE
58
    fpregs_format = 0;
59
#else
60
    fpregs_format = 1;
61
#endif
62
    qemu_put_be16s(f, &fpregs_format);
63

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

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

    
91
    qemu_put_be32s(f, &env->sysenter_cs);
92
    qemu_put_betls(f, &env->sysenter_esp);
93
    qemu_put_betls(f, &env->sysenter_eip);
94

    
95
    qemu_put_betls(f, &env->cr[0]);
96
    qemu_put_betls(f, &env->cr[2]);
97
    qemu_put_betls(f, &env->cr[3]);
98
    qemu_put_betls(f, &env->cr[4]);
99

    
100
    for(i = 0; i < 8; i++)
101
        qemu_put_betls(f, &env->dr[i]);
102

    
103
    /* MMU */
104
    a20_mask = (int32_t) env->a20_mask;
105
    qemu_put_sbe32s(f, &a20_mask);
106

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

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

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

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

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

    
155
#define MANTD1(fp)        (fp & ((1LL << 52) - 1))
156
#define EXPBIAS1 1023
157
#define EXPD1(fp)        ((fp >> 52) & 0x7FF)
158
#define SIGND1(fp)        ((fp >> 32) & 0x80000000)
159

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

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

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

    
189
    qemu_get_be16s(f, &fpuc);
190
    qemu_get_be16s(f, &fpus);
191
    qemu_get_be16s(f, &fptag);
192
    qemu_get_be16s(f, &fpregs_format);
193

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

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

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

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

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

    
264
    qemu_get_betls(f, &env->cr[0]);
265
    qemu_get_betls(f, &env->cr[2]);
266
    qemu_get_betls(f, &env->cr[3]);
267
    qemu_get_betls(f, &env->cr[4]);
268

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

    
276
    /* MMU */
277
    qemu_get_sbe32s(f, &a20_mask);
278
    env->a20_mask = a20_mask;
279

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

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

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

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

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