Statistics
| Branch: | Revision:

root / target-i386 / machine.c @ 8dd3dca3

History | View | Annotate | Download (6.9 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
    int i;
36

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

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

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

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

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

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

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

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

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

    
102
    /* MMU */
103
    qemu_put_be32s(f, &env->a20_mask);
104

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

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

    
123
#ifdef USE_X86LDOUBLE
124
/* XXX: add that in a FPU generic layer */
125
union x86_longdouble {
126
    uint64_t mant;
127
    uint16_t exp;
128
};
129

    
130
#define MANTD1(fp)        (fp & ((1LL << 52) - 1))
131
#define EXPBIAS1 1023
132
#define EXPD1(fp)        ((fp >> 52) & 0x7FF)
133
#define SIGND1(fp)        ((fp >> 32) & 0x80000000)
134

    
135
static void fp64_to_fp80(union x86_longdouble *p, uint64_t temp)
136
{
137
    int e;
138
    /* mantissa */
139
    p->mant = (MANTD1(temp) << 11) | (1LL << 63);
140
    /* exponent + sign */
141
    e = EXPD1(temp) - EXPBIAS1 + 16383;
142
    e |= SIGND1(temp) >> 16;
143
    p->exp = e;
144
}
145
#endif
146

    
147
int cpu_load(QEMUFile *f, void *opaque, int version_id)
148
{
149
    CPUState *env = opaque;
150
    int i, guess_mmx;
151
    uint32_t hflags;
152
    uint16_t fpus, fpuc, fptag, fpregs_format;
153

    
154
    if (version_id != 3 && version_id != 4)
155
        return -EINVAL;
156
    for(i = 0; i < CPU_NB_REGS; i++)
157
        qemu_get_betls(f, &env->regs[i]);
158
    qemu_get_betls(f, &env->eip);
159
    qemu_get_betls(f, &env->eflags);
160
    qemu_get_be32s(f, &hflags);
161

    
162
    qemu_get_be16s(f, &fpuc);
163
    qemu_get_be16s(f, &fpus);
164
    qemu_get_be16s(f, &fptag);
165
    qemu_get_be16s(f, &fpregs_format);
166

    
167
    /* NOTE: we cannot always restore the FPU state if the image come
168
       from a host with a different 'USE_X86LDOUBLE' define. We guess
169
       if we are in an MMX state to restore correctly in that case. */
170
    guess_mmx = ((fptag == 0xff) && (fpus & 0x3800) == 0);
171
    for(i = 0; i < 8; i++) {
172
        uint64_t mant;
173
        uint16_t exp;
174

    
175
        switch(fpregs_format) {
176
        case 0:
177
            mant = qemu_get_be64(f);
178
            exp = qemu_get_be16(f);
179
#ifdef USE_X86LDOUBLE
180
            env->fpregs[i].d = cpu_set_fp80(mant, exp);
181
#else
182
            /* difficult case */
183
            if (guess_mmx)
184
                env->fpregs[i].mmx.MMX_Q(0) = mant;
185
            else
186
                env->fpregs[i].d = cpu_set_fp80(mant, exp);
187
#endif
188
            break;
189
        case 1:
190
            mant = qemu_get_be64(f);
191
#ifdef USE_X86LDOUBLE
192
            {
193
                union x86_longdouble *p;
194
                /* difficult case */
195
                p = (void *)&env->fpregs[i];
196
                if (guess_mmx) {
197
                    p->mant = mant;
198
                    p->exp = 0xffff;
199
                } else {
200
                    fp64_to_fp80(p, mant);
201
                }
202
            }
203
#else
204
            env->fpregs[i].mmx.MMX_Q(0) = mant;
205
#endif
206
            break;
207
        default:
208
            return -EINVAL;
209
        }
210
    }
211

    
212
    env->fpuc = fpuc;
213
    /* XXX: restore FPU round state */
214
    env->fpstt = (fpus >> 11) & 7;
215
    env->fpus = fpus & ~0x3800;
216
    fptag ^= 0xff;
217
    for(i = 0; i < 8; i++) {
218
        env->fptags[i] = (fptag >> i) & 1;
219
    }
220

    
221
    for(i = 0; i < 6; i++)
222
        cpu_get_seg(f, &env->segs[i]);
223
    cpu_get_seg(f, &env->ldt);
224
    cpu_get_seg(f, &env->tr);
225
    cpu_get_seg(f, &env->gdt);
226
    cpu_get_seg(f, &env->idt);
227

    
228
    qemu_get_be32s(f, &env->sysenter_cs);
229
    qemu_get_be32s(f, &env->sysenter_esp);
230
    qemu_get_be32s(f, &env->sysenter_eip);
231

    
232
    qemu_get_betls(f, &env->cr[0]);
233
    qemu_get_betls(f, &env->cr[2]);
234
    qemu_get_betls(f, &env->cr[3]);
235
    qemu_get_betls(f, &env->cr[4]);
236

    
237
    for(i = 0; i < 8; i++)
238
        qemu_get_betls(f, &env->dr[i]);
239

    
240
    /* MMU */
241
    qemu_get_be32s(f, &env->a20_mask);
242

    
243
    qemu_get_be32s(f, &env->mxcsr);
244
    for(i = 0; i < CPU_NB_REGS; i++) {
245
        qemu_get_be64s(f, &env->xmm_regs[i].XMM_Q(0));
246
        qemu_get_be64s(f, &env->xmm_regs[i].XMM_Q(1));
247
    }
248

    
249
#ifdef TARGET_X86_64
250
    qemu_get_be64s(f, &env->efer);
251
    qemu_get_be64s(f, &env->star);
252
    qemu_get_be64s(f, &env->lstar);
253
    qemu_get_be64s(f, &env->cstar);
254
    qemu_get_be64s(f, &env->fmask);
255
    qemu_get_be64s(f, &env->kernelgsbase);
256
#endif
257
    if (version_id >= 4)
258
        qemu_get_be32s(f, &env->smbase);
259

    
260
    /* XXX: compute hflags from scratch, except for CPL and IIF */
261
    env->hflags = hflags;
262
    tlb_flush(env, 1);
263
    return 0;
264
}