1 /* 2 * This work is licensed under the terms of the GNU GPL, version 2 or later. 3 * See the COPYING file in the top-level directory. 4 */ 5 #include "qemu/osdep.h" 6 7 #include "cpu.h" 8 9 void x86_cpu_xsave_all_areas(X86CPU *cpu, void *buf, uint32_t buflen) 10 { 11 CPUX86State *env = &cpu->env; 12 const ExtSaveArea *e, *f; 13 int i; 14 15 X86LegacyXSaveArea *legacy; 16 X86XSaveHeader *header; 17 uint16_t cwd, swd, twd; 18 19 memset(buf, 0, buflen); 20 21 e = &x86_ext_save_areas[XSTATE_FP_BIT]; 22 23 legacy = buf + e->offset; 24 header = buf + e->offset + sizeof(*legacy); 25 26 twd = 0; 27 swd = env->fpus & ~(7 << 11); 28 swd |= (env->fpstt & 7) << 11; 29 cwd = env->fpuc; 30 for (i = 0; i < 8; ++i) { 31 twd |= (!env->fptags[i]) << i; 32 } 33 legacy->fcw = cwd; 34 legacy->fsw = swd; 35 legacy->ftw = twd; 36 legacy->fpop = env->fpop; 37 legacy->fpip = env->fpip; 38 legacy->fpdp = env->fpdp; 39 memcpy(&legacy->fpregs, env->fpregs, 40 sizeof(env->fpregs)); 41 legacy->mxcsr = env->mxcsr; 42 43 for (i = 0; i < CPU_NB_REGS; i++) { 44 uint8_t *xmm = legacy->xmm_regs[i]; 45 46 stq_p(xmm, env->xmm_regs[i].ZMM_Q(0)); 47 stq_p(xmm + 8, env->xmm_regs[i].ZMM_Q(1)); 48 } 49 50 header->xstate_bv = env->xstate_bv; 51 52 e = &x86_ext_save_areas[XSTATE_YMM_BIT]; 53 if (e->size && e->offset) { 54 XSaveAVX *avx; 55 56 avx = buf + e->offset; 57 58 for (i = 0; i < CPU_NB_REGS; i++) { 59 uint8_t *ymmh = avx->ymmh[i]; 60 61 stq_p(ymmh, env->xmm_regs[i].ZMM_Q(2)); 62 stq_p(ymmh + 8, env->xmm_regs[i].ZMM_Q(3)); 63 } 64 } 65 66 e = &x86_ext_save_areas[XSTATE_BNDREGS_BIT]; 67 if (e->size && e->offset) { 68 XSaveBNDREG *bndreg; 69 XSaveBNDCSR *bndcsr; 70 71 f = &x86_ext_save_areas[XSTATE_BNDCSR_BIT]; 72 assert(f->size); 73 assert(f->offset); 74 75 bndreg = buf + e->offset; 76 bndcsr = buf + f->offset; 77 78 memcpy(&bndreg->bnd_regs, env->bnd_regs, 79 sizeof(env->bnd_regs)); 80 bndcsr->bndcsr = env->bndcs_regs; 81 } 82 83 e = &x86_ext_save_areas[XSTATE_OPMASK_BIT]; 84 if (e->size && e->offset) { 85 XSaveOpmask *opmask; 86 XSaveZMM_Hi256 *zmm_hi256; 87 #ifdef TARGET_X86_64 88 XSaveHi16_ZMM *hi16_zmm; 89 #endif 90 91 f = &x86_ext_save_areas[XSTATE_ZMM_Hi256_BIT]; 92 assert(f->size); 93 assert(f->offset); 94 95 opmask = buf + e->offset; 96 zmm_hi256 = buf + f->offset; 97 98 memcpy(&opmask->opmask_regs, env->opmask_regs, 99 sizeof(env->opmask_regs)); 100 101 for (i = 0; i < CPU_NB_REGS; i++) { 102 uint8_t *zmmh = zmm_hi256->zmm_hi256[i]; 103 104 stq_p(zmmh, env->xmm_regs[i].ZMM_Q(4)); 105 stq_p(zmmh + 8, env->xmm_regs[i].ZMM_Q(5)); 106 stq_p(zmmh + 16, env->xmm_regs[i].ZMM_Q(6)); 107 stq_p(zmmh + 24, env->xmm_regs[i].ZMM_Q(7)); 108 } 109 110 #ifdef TARGET_X86_64 111 f = &x86_ext_save_areas[XSTATE_Hi16_ZMM_BIT]; 112 assert(f->size); 113 assert(f->offset); 114 115 hi16_zmm = buf + f->offset; 116 117 memcpy(&hi16_zmm->hi16_zmm, &env->xmm_regs[16], 118 16 * sizeof(env->xmm_regs[16])); 119 #endif 120 } 121 122 #ifdef TARGET_X86_64 123 e = &x86_ext_save_areas[XSTATE_PKRU_BIT]; 124 if (e->size && e->offset) { 125 XSavePKRU *pkru = buf + e->offset; 126 127 memcpy(pkru, &env->pkru, sizeof(env->pkru)); 128 } 129 #endif 130 } 131 132 void x86_cpu_xrstor_all_areas(X86CPU *cpu, const void *buf, uint32_t buflen) 133 { 134 CPUX86State *env = &cpu->env; 135 const ExtSaveArea *e, *f, *g; 136 int i; 137 138 const X86LegacyXSaveArea *legacy; 139 const X86XSaveHeader *header; 140 uint16_t cwd, swd, twd; 141 142 e = &x86_ext_save_areas[XSTATE_FP_BIT]; 143 144 legacy = buf + e->offset; 145 header = buf + e->offset + sizeof(*legacy); 146 147 cwd = legacy->fcw; 148 swd = legacy->fsw; 149 twd = legacy->ftw; 150 env->fpop = legacy->fpop; 151 env->fpstt = (swd >> 11) & 7; 152 env->fpus = swd; 153 env->fpuc = cwd; 154 for (i = 0; i < 8; ++i) { 155 env->fptags[i] = !((twd >> i) & 1); 156 } 157 env->fpip = legacy->fpip; 158 env->fpdp = legacy->fpdp; 159 env->mxcsr = legacy->mxcsr; 160 memcpy(env->fpregs, &legacy->fpregs, 161 sizeof(env->fpregs)); 162 163 for (i = 0; i < CPU_NB_REGS; i++) { 164 const uint8_t *xmm = legacy->xmm_regs[i]; 165 166 env->xmm_regs[i].ZMM_Q(0) = ldq_p(xmm); 167 env->xmm_regs[i].ZMM_Q(1) = ldq_p(xmm + 8); 168 } 169 170 env->xstate_bv = header->xstate_bv; 171 172 e = &x86_ext_save_areas[XSTATE_YMM_BIT]; 173 if (e->size && e->offset) { 174 const XSaveAVX *avx; 175 176 avx = buf + e->offset; 177 for (i = 0; i < CPU_NB_REGS; i++) { 178 const uint8_t *ymmh = avx->ymmh[i]; 179 180 env->xmm_regs[i].ZMM_Q(2) = ldq_p(ymmh); 181 env->xmm_regs[i].ZMM_Q(3) = ldq_p(ymmh + 8); 182 } 183 } 184 185 e = &x86_ext_save_areas[XSTATE_BNDREGS_BIT]; 186 if (e->size && e->offset) { 187 const XSaveBNDREG *bndreg; 188 const XSaveBNDCSR *bndcsr; 189 190 f = &x86_ext_save_areas[XSTATE_BNDCSR_BIT]; 191 assert(f->size); 192 assert(f->offset); 193 194 bndreg = buf + e->offset; 195 bndcsr = buf + f->offset; 196 197 memcpy(env->bnd_regs, &bndreg->bnd_regs, 198 sizeof(env->bnd_regs)); 199 env->bndcs_regs = bndcsr->bndcsr; 200 } 201 202 e = &x86_ext_save_areas[XSTATE_OPMASK_BIT]; 203 if (e->size && e->offset) { 204 const XSaveOpmask *opmask; 205 const XSaveZMM_Hi256 *zmm_hi256; 206 #ifdef TARGET_X86_64 207 const XSaveHi16_ZMM *hi16_zmm; 208 #endif 209 210 f = &x86_ext_save_areas[XSTATE_ZMM_Hi256_BIT]; 211 assert(f->size); 212 assert(f->offset); 213 214 g = &x86_ext_save_areas[XSTATE_Hi16_ZMM_BIT]; 215 assert(g->size); 216 assert(g->offset); 217 218 opmask = buf + e->offset; 219 zmm_hi256 = buf + f->offset; 220 #ifdef TARGET_X86_64 221 hi16_zmm = buf + g->offset; 222 #endif 223 224 memcpy(env->opmask_regs, &opmask->opmask_regs, 225 sizeof(env->opmask_regs)); 226 227 for (i = 0; i < CPU_NB_REGS; i++) { 228 const uint8_t *zmmh = zmm_hi256->zmm_hi256[i]; 229 230 env->xmm_regs[i].ZMM_Q(4) = ldq_p(zmmh); 231 env->xmm_regs[i].ZMM_Q(5) = ldq_p(zmmh + 8); 232 env->xmm_regs[i].ZMM_Q(6) = ldq_p(zmmh + 16); 233 env->xmm_regs[i].ZMM_Q(7) = ldq_p(zmmh + 24); 234 } 235 236 #ifdef TARGET_X86_64 237 memcpy(&env->xmm_regs[16], &hi16_zmm->hi16_zmm, 238 16 * sizeof(env->xmm_regs[16])); 239 #endif 240 } 241 242 #ifdef TARGET_X86_64 243 e = &x86_ext_save_areas[XSTATE_PKRU_BIT]; 244 if (e->size && e->offset) { 245 const XSavePKRU *pkru; 246 247 pkru = buf + e->offset; 248 memcpy(&env->pkru, pkru, sizeof(env->pkru)); 249 } 250 #endif 251 } 252