Revision 664e0f19 vl.c

b/vl.c
2082 2082
void cpu_save(QEMUFile *f, void *opaque)
2083 2083
{
2084 2084
    CPUState *env = opaque;
2085
    uint16_t fptag, fpus, fpuc;
2085
    uint16_t fptag, fpus, fpuc, fpregs_format;
2086 2086
    uint32_t hflags;
2087 2087
    int i;
2088

  
2088
    
2089 2089
    for(i = 0; i < CPU_NB_REGS; i++)
2090 2090
        qemu_put_betls(f, &env->regs[i]);
2091 2091
    qemu_put_betls(f, &env->eip);
2092 2092
    qemu_put_betls(f, &env->eflags);
2093
    qemu_put_betl(f, 0); /* XXX: suppress that */
2094 2093
    hflags = env->hflags; /* XXX: suppress most of the redundant hflags */
2095 2094
    qemu_put_be32s(f, &hflags);
2096 2095
    
......
2098 2097
    fpuc = env->fpuc;
2099 2098
    fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
2100 2099
    fptag = 0;
2101
    for (i=7; i>=0; i--) {
2102
	fptag <<= 2;
2103
	if (env->fptags[i]) {
2104
            fptag |= 3;
2105
        }
2100
    for(i = 0; i < 8; i++) {
2101
        fptag |= ((!env->fptags[i]) << i);
2106 2102
    }
2107 2103
    
2108 2104
    qemu_put_be16s(f, &fpuc);
2109 2105
    qemu_put_be16s(f, &fpus);
2110 2106
    qemu_put_be16s(f, &fptag);
2111 2107

  
2108
#ifdef USE_X86LDOUBLE
2109
    fpregs_format = 0;
2110
#else
2111
    fpregs_format = 1;
2112
#endif
2113
    qemu_put_be16s(f, &fpregs_format);
2114
    
2112 2115
    for(i = 0; i < 8; i++) {
2113 2116
        uint64_t mant;
2114 2117
        uint16_t exp;
2115
        cpu_get_fp80(&mant, &exp, env->fpregs[i]);
2118
#ifdef USE_X86LDOUBLE
2119
        /* we save the real CPU data (in case of MMX usage only 'mant'
2120
           contains the MMX register */
2121
        cpu_get_fp80(&mant, &exp, env->fpregs[i].d);
2116 2122
        qemu_put_be64(f, mant);
2117 2123
        qemu_put_be16(f, exp);
2124
#else
2125
        /* if we use doubles for float emulation, we save the doubles to
2126
           avoid losing information in case of MMX usage. It can give
2127
           problems if the image is restored on a CPU where long
2128
           doubles are used instead. */
2129
        qemu_put_be64(f, env->fpregs[i].xmm.MMX_Q(0));
2130
#endif
2118 2131
    }
2119 2132

  
2120 2133
    for(i = 0; i < 6; i++)
......
2139 2152
    /* MMU */
2140 2153
    qemu_put_be32s(f, &env->a20_mask);
2141 2154

  
2142
#ifdef TARGET_X86_64
2155
    /* XMM */
2156
    qemu_put_be32s(f, &env->mxcsr);
2143 2157
    for(i = 0; i < CPU_NB_REGS; i++) {
2144 2158
        qemu_put_be64s(f, &env->xmm_regs[i].XMM_Q(0));
2145 2159
        qemu_put_be64s(f, &env->xmm_regs[i].XMM_Q(1));
2146 2160
    }
2147 2161

  
2162
#ifdef TARGET_X86_64
2148 2163
    qemu_put_be64s(f, &env->efer);
2149 2164
    qemu_put_be64s(f, &env->star);
2150 2165
    qemu_put_be64s(f, &env->lstar);
......
2154 2169
#endif
2155 2170
}
2156 2171

  
2172
/* XXX: add that in a FPU generic layer */
2173
union x86_longdouble {
2174
    uint64_t mant;
2175
    uint16_t exp;
2176
};
2177

  
2178
#define MANTD1(fp)	(fp & ((1LL << 52) - 1))
2179
#define EXPBIAS1 1023
2180
#define EXPD1(fp)	((fp >> 52) & 0x7FF)
2181
#define SIGND1(fp)	((fp >> 32) & 0x80000000)
2182

  
2183
static void fp64_to_fp80(union x86_longdouble *p, uint64_t temp)
2184
{
2185
    int e;
2186
    /* mantissa */
2187
    p->mant = (MANTD1(temp) << 11) | (1LL << 63);
2188
    /* exponent + sign */
2189
    e = EXPD1(temp) - EXPBIAS1 + 16383;
2190
    e |= SIGND1(temp) >> 16;
2191
    p->exp = e;
2192
}
2193

  
2157 2194
int cpu_load(QEMUFile *f, void *opaque, int version_id)
2158 2195
{
2159 2196
    CPUState *env = opaque;
2160
    int i;
2197
    int i, guess_mmx;
2161 2198
    uint32_t hflags;
2162
    uint16_t fpus, fpuc, fptag;
2199
    uint16_t fpus, fpuc, fptag, fpregs_format;
2163 2200

  
2164
    if (version_id != 2)
2201
    if (version_id != 3)
2165 2202
        return -EINVAL;
2166 2203
    for(i = 0; i < CPU_NB_REGS; i++)
2167 2204
        qemu_get_betls(f, &env->regs[i]);
2168 2205
    qemu_get_betls(f, &env->eip);
2169 2206
    qemu_get_betls(f, &env->eflags);
2170
    qemu_get_betl(f); /* XXX: suppress that */
2171 2207
    qemu_get_be32s(f, &hflags);
2172 2208

  
2173 2209
    qemu_get_be16s(f, &fpuc);
2174 2210
    qemu_get_be16s(f, &fpus);
2175 2211
    qemu_get_be16s(f, &fptag);
2176

  
2212
    qemu_get_be16s(f, &fpregs_format);
2213
    
2214
    /* NOTE: we cannot always restore the FPU state if the image come
2215
       from a host with a different 'USE_X86LDOUBLE' define. We guess
2216
       if we are in an MMX state to restore correctly in that case. */
2217
    guess_mmx = ((fptag == 0xff) && (fpus & 0x3800) == 0);
2177 2218
    for(i = 0; i < 8; i++) {
2178 2219
        uint64_t mant;
2179 2220
        uint16_t exp;
2180
        mant = qemu_get_be64(f);
2181
        exp = qemu_get_be16(f);
2182
        env->fpregs[i] = cpu_set_fp80(mant, exp);
2221
        union x86_longdouble *p;
2222
        
2223
        switch(fpregs_format) {
2224
        case 0:
2225
            mant = qemu_get_be64(f);
2226
            exp = qemu_get_be16(f);
2227
#ifdef USE_X86LDOUBLE
2228
            env->fpregs[i].d = cpu_set_fp80(mant, exp);
2229
#else
2230
            /* difficult case */
2231
            if (guess_mmx)
2232
                env->fpregs[i].xmm.MMX_Q(0) = mant;
2233
            else
2234
                env->fpregs[i].d = cpu_set_fp80(mant, exp);
2235
#endif
2236
            break;
2237
        case 1:
2238
            mant = qemu_get_be64(f);
2239
#ifdef USE_X86LDOUBLE
2240
            /* difficult case */
2241
            p = (void *)&env->fpregs[i];
2242
            if (guess_mmx) {
2243
                p->mant = mant;
2244
                p->exp = 0xffff;
2245
            } else {
2246
                fp64_to_fp80(p, mant);
2247
            }
2248
#else
2249
            env->fpregs[i].xmm.MMX_Q(0) = mant;
2250
#endif            
2251
            break;
2252
        default:
2253
            return -EINVAL;
2254
        }
2183 2255
    }
2184 2256

  
2185 2257
    env->fpuc = fpuc;
2186 2258
    env->fpstt = (fpus >> 11) & 7;
2187 2259
    env->fpus = fpus & ~0x3800;
2260
    fptag ^= 0xff;
2188 2261
    for(i = 0; i < 8; i++) {
2189
        env->fptags[i] = ((fptag & 3) == 3);
2190
        fptag >>= 2;
2262
        env->fptags[i] = (fptag >> i) & 1;
2191 2263
    }
2192 2264
    
2193 2265
    for(i = 0; i < 6; i++)
......
2212 2284
    /* MMU */
2213 2285
    qemu_get_be32s(f, &env->a20_mask);
2214 2286

  
2215
#ifdef TARGET_X86_64
2287
    qemu_get_be32s(f, &env->mxcsr);
2216 2288
    for(i = 0; i < CPU_NB_REGS; i++) {
2217 2289
        qemu_get_be64s(f, &env->xmm_regs[i].XMM_Q(0));
2218 2290
        qemu_get_be64s(f, &env->xmm_regs[i].XMM_Q(1));
2219 2291
    }
2220 2292

  
2293
#ifdef TARGET_X86_64
2221 2294
    qemu_get_be64s(f, &env->efer);
2222 2295
    qemu_get_be64s(f, &env->star);
2223 2296
    qemu_get_be64s(f, &env->lstar);
......
3433 3506
    cpu_single_env = env;
3434 3507

  
3435 3508
    register_savevm("timer", 0, 1, timer_save, timer_load, env);
3436
    register_savevm("cpu", 0, 2, cpu_save, cpu_load, env);
3509
    register_savevm("cpu", 0, 3, cpu_save, cpu_load, env);
3437 3510
    register_savevm("ram", 0, 1, ram_save, ram_load, NULL);
3438 3511
    qemu_register_reset(main_cpu_reset, global_env);
3439 3512

  

Also available in: Unified diff