2082 |
void cpu_save(QEMUFile *f, void *opaque) |
void cpu_save(QEMUFile *f, void *opaque) |
2083 |
{ |
{ |
2084 |
CPUState *env = opaque; |
CPUState *env = opaque; |
2085 |
uint16_t fptag, fpus, fpuc; |
uint16_t fptag, fpus, fpuc, fpregs_format; |
2086 |
uint32_t hflags; |
uint32_t hflags; |
2087 |
int i; |
int i; |
2088 |
|
|
2089 |
for(i = 0; i < CPU_NB_REGS; i++) |
for(i = 0; i < CPU_NB_REGS; i++) |
2090 |
qemu_put_betls(f, &env->regs[i]); |
qemu_put_betls(f, &env->regs[i]); |
2091 |
qemu_put_betls(f, &env->eip); |
qemu_put_betls(f, &env->eip); |
2092 |
qemu_put_betls(f, &env->eflags); |
qemu_put_betls(f, &env->eflags); |
|
qemu_put_betl(f, 0); /* XXX: suppress that */ |
|
2093 |
hflags = env->hflags; /* XXX: suppress most of the redundant hflags */ |
hflags = env->hflags; /* XXX: suppress most of the redundant hflags */ |
2094 |
qemu_put_be32s(f, &hflags); |
qemu_put_be32s(f, &hflags); |
2095 |
|
|
2097 |
fpuc = env->fpuc; |
fpuc = env->fpuc; |
2098 |
fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; |
fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; |
2099 |
fptag = 0; |
fptag = 0; |
2100 |
for (i=7; i>=0; i--) { |
for(i = 0; i < 8; i++) { |
2101 |
fptag <<= 2; |
fptag |= ((!env->fptags[i]) << i); |
|
if (env->fptags[i]) { |
|
|
fptag |= 3; |
|
|
} |
|
2102 |
} |
} |
2103 |
|
|
2104 |
qemu_put_be16s(f, &fpuc); |
qemu_put_be16s(f, &fpuc); |
2105 |
qemu_put_be16s(f, &fpus); |
qemu_put_be16s(f, &fpus); |
2106 |
qemu_put_be16s(f, &fptag); |
qemu_put_be16s(f, &fptag); |
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 |
|
|
2115 |
for(i = 0; i < 8; i++) { |
for(i = 0; i < 8; i++) { |
2116 |
uint64_t mant; |
uint64_t mant; |
2117 |
uint16_t exp; |
uint16_t exp; |
2118 |
cpu_get_fp80(&mant, &exp, env->fpregs[i]); |
#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); |
2122 |
qemu_put_be64(f, mant); |
qemu_put_be64(f, mant); |
2123 |
qemu_put_be16(f, exp); |
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 |
2131 |
} |
} |
2132 |
|
|
2133 |
for(i = 0; i < 6; i++) |
for(i = 0; i < 6; i++) |
2152 |
/* MMU */ |
/* MMU */ |
2153 |
qemu_put_be32s(f, &env->a20_mask); |
qemu_put_be32s(f, &env->a20_mask); |
2154 |
|
|
2155 |
#ifdef TARGET_X86_64 |
/* XMM */ |
2156 |
|
qemu_put_be32s(f, &env->mxcsr); |
2157 |
for(i = 0; i < CPU_NB_REGS; i++) { |
for(i = 0; i < CPU_NB_REGS; i++) { |
2158 |
qemu_put_be64s(f, &env->xmm_regs[i].XMM_Q(0)); |
qemu_put_be64s(f, &env->xmm_regs[i].XMM_Q(0)); |
2159 |
qemu_put_be64s(f, &env->xmm_regs[i].XMM_Q(1)); |
qemu_put_be64s(f, &env->xmm_regs[i].XMM_Q(1)); |
2160 |
} |
} |
2161 |
|
|
2162 |
|
#ifdef TARGET_X86_64 |
2163 |
qemu_put_be64s(f, &env->efer); |
qemu_put_be64s(f, &env->efer); |
2164 |
qemu_put_be64s(f, &env->star); |
qemu_put_be64s(f, &env->star); |
2165 |
qemu_put_be64s(f, &env->lstar); |
qemu_put_be64s(f, &env->lstar); |
2169 |
#endif |
#endif |
2170 |
} |
} |
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 |
|
|
2194 |
int cpu_load(QEMUFile *f, void *opaque, int version_id) |
int cpu_load(QEMUFile *f, void *opaque, int version_id) |
2195 |
{ |
{ |
2196 |
CPUState *env = opaque; |
CPUState *env = opaque; |
2197 |
int i; |
int i, guess_mmx; |
2198 |
uint32_t hflags; |
uint32_t hflags; |
2199 |
uint16_t fpus, fpuc, fptag; |
uint16_t fpus, fpuc, fptag, fpregs_format; |
2200 |
|
|
2201 |
if (version_id != 2) |
if (version_id != 3) |
2202 |
return -EINVAL; |
return -EINVAL; |
2203 |
for(i = 0; i < CPU_NB_REGS; i++) |
for(i = 0; i < CPU_NB_REGS; i++) |
2204 |
qemu_get_betls(f, &env->regs[i]); |
qemu_get_betls(f, &env->regs[i]); |
2205 |
qemu_get_betls(f, &env->eip); |
qemu_get_betls(f, &env->eip); |
2206 |
qemu_get_betls(f, &env->eflags); |
qemu_get_betls(f, &env->eflags); |
|
qemu_get_betl(f); /* XXX: suppress that */ |
|
2207 |
qemu_get_be32s(f, &hflags); |
qemu_get_be32s(f, &hflags); |
2208 |
|
|
2209 |
qemu_get_be16s(f, &fpuc); |
qemu_get_be16s(f, &fpuc); |
2210 |
qemu_get_be16s(f, &fpus); |
qemu_get_be16s(f, &fpus); |
2211 |
qemu_get_be16s(f, &fptag); |
qemu_get_be16s(f, &fptag); |
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); |
2218 |
for(i = 0; i < 8; i++) { |
for(i = 0; i < 8; i++) { |
2219 |
uint64_t mant; |
uint64_t mant; |
2220 |
uint16_t exp; |
uint16_t exp; |
2221 |
mant = qemu_get_be64(f); |
union x86_longdouble *p; |
2222 |
exp = qemu_get_be16(f); |
|
2223 |
env->fpregs[i] = cpu_set_fp80(mant, exp); |
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 |
|
} |
2255 |
} |
} |
2256 |
|
|
2257 |
env->fpuc = fpuc; |
env->fpuc = fpuc; |
2258 |
env->fpstt = (fpus >> 11) & 7; |
env->fpstt = (fpus >> 11) & 7; |
2259 |
env->fpus = fpus & ~0x3800; |
env->fpus = fpus & ~0x3800; |
2260 |
|
fptag ^= 0xff; |
2261 |
for(i = 0; i < 8; i++) { |
for(i = 0; i < 8; i++) { |
2262 |
env->fptags[i] = ((fptag & 3) == 3); |
env->fptags[i] = (fptag >> i) & 1; |
|
fptag >>= 2; |
|
2263 |
} |
} |
2264 |
|
|
2265 |
for(i = 0; i < 6; i++) |
for(i = 0; i < 6; i++) |
2284 |
/* MMU */ |
/* MMU */ |
2285 |
qemu_get_be32s(f, &env->a20_mask); |
qemu_get_be32s(f, &env->a20_mask); |
2286 |
|
|
2287 |
#ifdef TARGET_X86_64 |
qemu_get_be32s(f, &env->mxcsr); |
2288 |
for(i = 0; i < CPU_NB_REGS; i++) { |
for(i = 0; i < CPU_NB_REGS; i++) { |
2289 |
qemu_get_be64s(f, &env->xmm_regs[i].XMM_Q(0)); |
qemu_get_be64s(f, &env->xmm_regs[i].XMM_Q(0)); |
2290 |
qemu_get_be64s(f, &env->xmm_regs[i].XMM_Q(1)); |
qemu_get_be64s(f, &env->xmm_regs[i].XMM_Q(1)); |
2291 |
} |
} |
2292 |
|
|
2293 |
|
#ifdef TARGET_X86_64 |
2294 |
qemu_get_be64s(f, &env->efer); |
qemu_get_be64s(f, &env->efer); |
2295 |
qemu_get_be64s(f, &env->star); |
qemu_get_be64s(f, &env->star); |
2296 |
qemu_get_be64s(f, &env->lstar); |
qemu_get_be64s(f, &env->lstar); |
3506 |
cpu_single_env = env; |
cpu_single_env = env; |
3507 |
|
|
3508 |
register_savevm("timer", 0, 1, timer_save, timer_load, env); |
register_savevm("timer", 0, 1, timer_save, timer_load, env); |
3509 |
register_savevm("cpu", 0, 2, cpu_save, cpu_load, env); |
register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); |
3510 |
register_savevm("ram", 0, 1, ram_save, ram_load, NULL); |
register_savevm("ram", 0, 1, ram_save, ram_load, NULL); |
3511 |
qemu_register_reset(main_cpu_reset, global_env); |
qemu_register_reset(main_cpu_reset, global_env); |
3512 |
|
|