|
|
1.1 ! root 1: /* ! 2: * i386 helpers ! 3: * ! 4: * Copyright (c) 2003 Fabrice Bellard ! 5: * ! 6: * This library is free software; you can redistribute it and/or ! 7: * modify it under the terms of the GNU Lesser General Public ! 8: * License as published by the Free Software Foundation; either ! 9: * version 2 of the License, or (at your option) any later version. ! 10: * ! 11: * This library is distributed in the hope that it will be useful, ! 12: * but WITHOUT ANY WARRANTY; without even the implied warranty of ! 13: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ! 14: * Lesser General Public License for more details. ! 15: * ! 16: * You should have received a copy of the GNU Lesser General Public ! 17: * License along with this library; if not, write to the Free Software ! 18: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA ! 19: */ ! 20: #define CPU_NO_GLOBAL_REGS ! 21: #include "exec.h" ! 22: #include "exec-all.h" ! 23: #include "host-utils.h" ! 24: ! 25: //#define DEBUG_PCALL ! 26: ! 27: ! 28: #ifdef DEBUG_PCALL ! 29: # define LOG_PCALL(...) qemu_log_mask(CPU_LOG_PCALL, ## __VA_ARGS__) ! 30: # define LOG_PCALL_STATE(env) \ ! 31: log_cpu_state_mask(CPU_LOG_PCALL, (env), X86_DUMP_CCOP) ! 32: #else ! 33: # define LOG_PCALL(...) do { } while (0) ! 34: # define LOG_PCALL_STATE(env) do { } while (0) ! 35: #endif ! 36: ! 37: ! 38: #if 0 ! 39: #define raise_exception_err(a, b)\ ! 40: do {\ ! 41: qemu_log("raise_exception line=%d\n", __LINE__);\ ! 42: (raise_exception_err)(a, b);\ ! 43: } while (0) ! 44: #endif ! 45: ! 46: static const uint8_t parity_table[256] = { ! 47: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ! 48: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ! 49: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ! 50: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ! 51: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ! 52: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ! 53: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ! 54: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ! 55: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ! 56: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ! 57: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ! 58: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ! 59: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ! 60: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ! 61: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ! 62: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ! 63: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ! 64: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ! 65: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ! 66: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ! 67: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ! 68: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ! 69: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ! 70: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ! 71: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ! 72: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ! 73: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ! 74: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ! 75: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ! 76: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ! 77: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ! 78: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ! 79: }; ! 80: ! 81: /* modulo 17 table */ ! 82: static const uint8_t rclw_table[32] = { ! 83: 0, 1, 2, 3, 4, 5, 6, 7, ! 84: 8, 9,10,11,12,13,14,15, ! 85: 16, 0, 1, 2, 3, 4, 5, 6, ! 86: 7, 8, 9,10,11,12,13,14, ! 87: }; ! 88: ! 89: /* modulo 9 table */ ! 90: static const uint8_t rclb_table[32] = { ! 91: 0, 1, 2, 3, 4, 5, 6, 7, ! 92: 8, 0, 1, 2, 3, 4, 5, 6, ! 93: 7, 8, 0, 1, 2, 3, 4, 5, ! 94: 6, 7, 8, 0, 1, 2, 3, 4, ! 95: }; ! 96: ! 97: static const CPU86_LDouble f15rk[7] = ! 98: { ! 99: 0.00000000000000000000L, ! 100: 1.00000000000000000000L, ! 101: 3.14159265358979323851L, /*pi*/ ! 102: 0.30102999566398119523L, /*lg2*/ ! 103: 0.69314718055994530943L, /*ln2*/ ! 104: 1.44269504088896340739L, /*l2e*/ ! 105: 3.32192809488736234781L, /*l2t*/ ! 106: }; ! 107: ! 108: /* broken thread support */ ! 109: ! 110: static spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED; ! 111: ! 112: void helper_lock(void) ! 113: { ! 114: spin_lock(&global_cpu_lock); ! 115: } ! 116: ! 117: void helper_unlock(void) ! 118: { ! 119: spin_unlock(&global_cpu_lock); ! 120: } ! 121: ! 122: void helper_write_eflags(target_ulong t0, uint32_t update_mask) ! 123: { ! 124: load_eflags(t0, update_mask); ! 125: } ! 126: ! 127: target_ulong helper_read_eflags(void) ! 128: { ! 129: uint32_t eflags; ! 130: eflags = helper_cc_compute_all(CC_OP); ! 131: eflags |= (DF & DF_MASK); ! 132: eflags |= env->eflags & ~(VM_MASK | RF_MASK); ! 133: return eflags; ! 134: } ! 135: ! 136: /* return non zero if error */ ! 137: static inline int load_segment(uint32_t *e1_ptr, uint32_t *e2_ptr, ! 138: int selector) ! 139: { ! 140: SegmentCache *dt; ! 141: int index; ! 142: target_ulong ptr; ! 143: ! 144: if (selector & 0x4) ! 145: dt = &env->ldt; ! 146: else ! 147: dt = &env->gdt; ! 148: index = selector & ~7; ! 149: if ((index + 7) > dt->limit) ! 150: return -1; ! 151: ptr = dt->base + index; ! 152: *e1_ptr = ldl_kernel(ptr); ! 153: *e2_ptr = ldl_kernel(ptr + 4); ! 154: return 0; ! 155: } ! 156: ! 157: static inline unsigned int get_seg_limit(uint32_t e1, uint32_t e2) ! 158: { ! 159: unsigned int limit; ! 160: limit = (e1 & 0xffff) | (e2 & 0x000f0000); ! 161: if (e2 & DESC_G_MASK) ! 162: limit = (limit << 12) | 0xfff; ! 163: return limit; ! 164: } ! 165: ! 166: static inline uint32_t get_seg_base(uint32_t e1, uint32_t e2) ! 167: { ! 168: return ((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000)); ! 169: } ! 170: ! 171: static inline void load_seg_cache_raw_dt(SegmentCache *sc, uint32_t e1, uint32_t e2) ! 172: { ! 173: sc->base = get_seg_base(e1, e2); ! 174: sc->limit = get_seg_limit(e1, e2); ! 175: sc->flags = e2; ! 176: } ! 177: ! 178: /* init the segment cache in vm86 mode. */ ! 179: static inline void load_seg_vm(int seg, int selector) ! 180: { ! 181: selector &= 0xffff; ! 182: cpu_x86_load_seg_cache(env, seg, selector, ! 183: (selector << 4), 0xffff, 0); ! 184: } ! 185: ! 186: static inline void get_ss_esp_from_tss(uint32_t *ss_ptr, ! 187: uint32_t *esp_ptr, int dpl) ! 188: { ! 189: int type, index, shift; ! 190: ! 191: #if 0 ! 192: { ! 193: int i; ! 194: printf("TR: base=%p limit=%x\n", env->tr.base, env->tr.limit); ! 195: for(i=0;i<env->tr.limit;i++) { ! 196: printf("%02x ", env->tr.base[i]); ! 197: if ((i & 7) == 7) printf("\n"); ! 198: } ! 199: printf("\n"); ! 200: } ! 201: #endif ! 202: ! 203: if (!(env->tr.flags & DESC_P_MASK)) ! 204: cpu_abort(env, "invalid tss"); ! 205: type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf; ! 206: if ((type & 7) != 1) ! 207: cpu_abort(env, "invalid tss type"); ! 208: shift = type >> 3; ! 209: index = (dpl * 4 + 2) << shift; ! 210: if (index + (4 << shift) - 1 > env->tr.limit) ! 211: raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc); ! 212: if (shift == 0) { ! 213: *esp_ptr = lduw_kernel(env->tr.base + index); ! 214: *ss_ptr = lduw_kernel(env->tr.base + index + 2); ! 215: } else { ! 216: *esp_ptr = ldl_kernel(env->tr.base + index); ! 217: *ss_ptr = lduw_kernel(env->tr.base + index + 4); ! 218: } ! 219: } ! 220: ! 221: /* XXX: merge with load_seg() */ ! 222: static void tss_load_seg(int seg_reg, int selector) ! 223: { ! 224: uint32_t e1, e2; ! 225: int rpl, dpl, cpl; ! 226: ! 227: if ((selector & 0xfffc) != 0) { ! 228: if (load_segment(&e1, &e2, selector) != 0) ! 229: raise_exception_err(EXCP0A_TSS, selector & 0xfffc); ! 230: if (!(e2 & DESC_S_MASK)) ! 231: raise_exception_err(EXCP0A_TSS, selector & 0xfffc); ! 232: rpl = selector & 3; ! 233: dpl = (e2 >> DESC_DPL_SHIFT) & 3; ! 234: cpl = env->hflags & HF_CPL_MASK; ! 235: if (seg_reg == R_CS) { ! 236: if (!(e2 & DESC_CS_MASK)) ! 237: raise_exception_err(EXCP0A_TSS, selector & 0xfffc); ! 238: /* XXX: is it correct ? */ ! 239: if (dpl != rpl) ! 240: raise_exception_err(EXCP0A_TSS, selector & 0xfffc); ! 241: if ((e2 & DESC_C_MASK) && dpl > rpl) ! 242: raise_exception_err(EXCP0A_TSS, selector & 0xfffc); ! 243: } else if (seg_reg == R_SS) { ! 244: /* SS must be writable data */ ! 245: if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK)) ! 246: raise_exception_err(EXCP0A_TSS, selector & 0xfffc); ! 247: if (dpl != cpl || dpl != rpl) ! 248: raise_exception_err(EXCP0A_TSS, selector & 0xfffc); ! 249: } else { ! 250: /* not readable code */ ! 251: if ((e2 & DESC_CS_MASK) && !(e2 & DESC_R_MASK)) ! 252: raise_exception_err(EXCP0A_TSS, selector & 0xfffc); ! 253: /* if data or non conforming code, checks the rights */ ! 254: if (((e2 >> DESC_TYPE_SHIFT) & 0xf) < 12) { ! 255: if (dpl < cpl || dpl < rpl) ! 256: raise_exception_err(EXCP0A_TSS, selector & 0xfffc); ! 257: } ! 258: } ! 259: if (!(e2 & DESC_P_MASK)) ! 260: raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); ! 261: cpu_x86_load_seg_cache(env, seg_reg, selector, ! 262: get_seg_base(e1, e2), ! 263: get_seg_limit(e1, e2), ! 264: e2); ! 265: } else { ! 266: if (seg_reg == R_SS || seg_reg == R_CS) ! 267: raise_exception_err(EXCP0A_TSS, selector & 0xfffc); ! 268: } ! 269: } ! 270: ! 271: #define SWITCH_TSS_JMP 0 ! 272: #define SWITCH_TSS_IRET 1 ! 273: #define SWITCH_TSS_CALL 2 ! 274: ! 275: /* XXX: restore CPU state in registers (PowerPC case) */ ! 276: static void switch_tss(int tss_selector, ! 277: uint32_t e1, uint32_t e2, int source, ! 278: uint32_t next_eip) ! 279: { ! 280: int tss_limit, tss_limit_max, type, old_tss_limit_max, old_type, v1, v2, i; ! 281: target_ulong tss_base; ! 282: uint32_t new_regs[8], new_segs[6]; ! 283: uint32_t new_eflags, new_eip, new_cr3, new_ldt, new_trap; ! 284: uint32_t old_eflags, eflags_mask; ! 285: SegmentCache *dt; ! 286: int index; ! 287: target_ulong ptr; ! 288: ! 289: type = (e2 >> DESC_TYPE_SHIFT) & 0xf; ! 290: LOG_PCALL("switch_tss: sel=0x%04x type=%d src=%d\n", tss_selector, type, source); ! 291: ! 292: /* if task gate, we read the TSS segment and we load it */ ! 293: if (type == 5) { ! 294: if (!(e2 & DESC_P_MASK)) ! 295: raise_exception_err(EXCP0B_NOSEG, tss_selector & 0xfffc); ! 296: tss_selector = e1 >> 16; ! 297: if (tss_selector & 4) ! 298: raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc); ! 299: if (load_segment(&e1, &e2, tss_selector) != 0) ! 300: raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc); ! 301: if (e2 & DESC_S_MASK) ! 302: raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc); ! 303: type = (e2 >> DESC_TYPE_SHIFT) & 0xf; ! 304: if ((type & 7) != 1) ! 305: raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc); ! 306: } ! 307: ! 308: if (!(e2 & DESC_P_MASK)) ! 309: raise_exception_err(EXCP0B_NOSEG, tss_selector & 0xfffc); ! 310: ! 311: if (type & 8) ! 312: tss_limit_max = 103; ! 313: else ! 314: tss_limit_max = 43; ! 315: tss_limit = get_seg_limit(e1, e2); ! 316: tss_base = get_seg_base(e1, e2); ! 317: if ((tss_selector & 4) != 0 || ! 318: tss_limit < tss_limit_max) ! 319: raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc); ! 320: old_type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf; ! 321: if (old_type & 8) ! 322: old_tss_limit_max = 103; ! 323: else ! 324: old_tss_limit_max = 43; ! 325: ! 326: /* read all the registers from the new TSS */ ! 327: if (type & 8) { ! 328: /* 32 bit */ ! 329: new_cr3 = ldl_kernel(tss_base + 0x1c); ! 330: new_eip = ldl_kernel(tss_base + 0x20); ! 331: new_eflags = ldl_kernel(tss_base + 0x24); ! 332: for(i = 0; i < 8; i++) ! 333: new_regs[i] = ldl_kernel(tss_base + (0x28 + i * 4)); ! 334: for(i = 0; i < 6; i++) ! 335: new_segs[i] = lduw_kernel(tss_base + (0x48 + i * 4)); ! 336: new_ldt = lduw_kernel(tss_base + 0x60); ! 337: new_trap = ldl_kernel(tss_base + 0x64); ! 338: } else { ! 339: /* 16 bit */ ! 340: new_cr3 = 0; ! 341: new_eip = lduw_kernel(tss_base + 0x0e); ! 342: new_eflags = lduw_kernel(tss_base + 0x10); ! 343: for(i = 0; i < 8; i++) ! 344: new_regs[i] = lduw_kernel(tss_base + (0x12 + i * 2)) | 0xffff0000; ! 345: for(i = 0; i < 4; i++) ! 346: new_segs[i] = lduw_kernel(tss_base + (0x22 + i * 4)); ! 347: new_ldt = lduw_kernel(tss_base + 0x2a); ! 348: new_segs[R_FS] = 0; ! 349: new_segs[R_GS] = 0; ! 350: new_trap = 0; ! 351: } ! 352: ! 353: /* NOTE: we must avoid memory exceptions during the task switch, ! 354: so we make dummy accesses before */ ! 355: /* XXX: it can still fail in some cases, so a bigger hack is ! 356: necessary to valid the TLB after having done the accesses */ ! 357: ! 358: v1 = ldub_kernel(env->tr.base); ! 359: v2 = ldub_kernel(env->tr.base + old_tss_limit_max); ! 360: stb_kernel(env->tr.base, v1); ! 361: stb_kernel(env->tr.base + old_tss_limit_max, v2); ! 362: ! 363: /* clear busy bit (it is restartable) */ ! 364: if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_IRET) { ! 365: target_ulong ptr; ! 366: uint32_t e2; ! 367: ptr = env->gdt.base + (env->tr.selector & ~7); ! 368: e2 = ldl_kernel(ptr + 4); ! 369: e2 &= ~DESC_TSS_BUSY_MASK; ! 370: stl_kernel(ptr + 4, e2); ! 371: } ! 372: old_eflags = compute_eflags(); ! 373: if (source == SWITCH_TSS_IRET) ! 374: old_eflags &= ~NT_MASK; ! 375: ! 376: /* save the current state in the old TSS */ ! 377: if (type & 8) { ! 378: /* 32 bit */ ! 379: stl_kernel(env->tr.base + 0x20, next_eip); ! 380: stl_kernel(env->tr.base + 0x24, old_eflags); ! 381: stl_kernel(env->tr.base + (0x28 + 0 * 4), EAX); ! 382: stl_kernel(env->tr.base + (0x28 + 1 * 4), ECX); ! 383: stl_kernel(env->tr.base + (0x28 + 2 * 4), EDX); ! 384: stl_kernel(env->tr.base + (0x28 + 3 * 4), EBX); ! 385: stl_kernel(env->tr.base + (0x28 + 4 * 4), ESP); ! 386: stl_kernel(env->tr.base + (0x28 + 5 * 4), EBP); ! 387: stl_kernel(env->tr.base + (0x28 + 6 * 4), ESI); ! 388: stl_kernel(env->tr.base + (0x28 + 7 * 4), EDI); ! 389: for(i = 0; i < 6; i++) ! 390: stw_kernel(env->tr.base + (0x48 + i * 4), env->segs[i].selector); ! 391: } else { ! 392: /* 16 bit */ ! 393: stw_kernel(env->tr.base + 0x0e, next_eip); ! 394: stw_kernel(env->tr.base + 0x10, old_eflags); ! 395: stw_kernel(env->tr.base + (0x12 + 0 * 2), EAX); ! 396: stw_kernel(env->tr.base + (0x12 + 1 * 2), ECX); ! 397: stw_kernel(env->tr.base + (0x12 + 2 * 2), EDX); ! 398: stw_kernel(env->tr.base + (0x12 + 3 * 2), EBX); ! 399: stw_kernel(env->tr.base + (0x12 + 4 * 2), ESP); ! 400: stw_kernel(env->tr.base + (0x12 + 5 * 2), EBP); ! 401: stw_kernel(env->tr.base + (0x12 + 6 * 2), ESI); ! 402: stw_kernel(env->tr.base + (0x12 + 7 * 2), EDI); ! 403: for(i = 0; i < 4; i++) ! 404: stw_kernel(env->tr.base + (0x22 + i * 4), env->segs[i].selector); ! 405: } ! 406: ! 407: /* now if an exception occurs, it will occurs in the next task ! 408: context */ ! 409: ! 410: if (source == SWITCH_TSS_CALL) { ! 411: stw_kernel(tss_base, env->tr.selector); ! 412: new_eflags |= NT_MASK; ! 413: } ! 414: ! 415: /* set busy bit */ ! 416: if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_CALL) { ! 417: target_ulong ptr; ! 418: uint32_t e2; ! 419: ptr = env->gdt.base + (tss_selector & ~7); ! 420: e2 = ldl_kernel(ptr + 4); ! 421: e2 |= DESC_TSS_BUSY_MASK; ! 422: stl_kernel(ptr + 4, e2); ! 423: } ! 424: ! 425: /* set the new CPU state */ ! 426: /* from this point, any exception which occurs can give problems */ ! 427: env->cr[0] |= CR0_TS_MASK; ! 428: env->hflags |= HF_TS_MASK; ! 429: env->tr.selector = tss_selector; ! 430: env->tr.base = tss_base; ! 431: env->tr.limit = tss_limit; ! 432: env->tr.flags = e2 & ~DESC_TSS_BUSY_MASK; ! 433: ! 434: if ((type & 8) && (env->cr[0] & CR0_PG_MASK)) { ! 435: cpu_x86_update_cr3(env, new_cr3); ! 436: } ! 437: ! 438: /* load all registers without an exception, then reload them with ! 439: possible exception */ ! 440: env->eip = new_eip; ! 441: eflags_mask = TF_MASK | AC_MASK | ID_MASK | ! 442: IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | NT_MASK; ! 443: if (!(type & 8)) ! 444: eflags_mask &= 0xffff; ! 445: load_eflags(new_eflags, eflags_mask); ! 446: /* XXX: what to do in 16 bit case ? */ ! 447: EAX = new_regs[0]; ! 448: ECX = new_regs[1]; ! 449: EDX = new_regs[2]; ! 450: EBX = new_regs[3]; ! 451: ESP = new_regs[4]; ! 452: EBP = new_regs[5]; ! 453: ESI = new_regs[6]; ! 454: EDI = new_regs[7]; ! 455: if (new_eflags & VM_MASK) { ! 456: for(i = 0; i < 6; i++) ! 457: load_seg_vm(i, new_segs[i]); ! 458: /* in vm86, CPL is always 3 */ ! 459: cpu_x86_set_cpl(env, 3); ! 460: } else { ! 461: /* CPL is set the RPL of CS */ ! 462: cpu_x86_set_cpl(env, new_segs[R_CS] & 3); ! 463: /* first just selectors as the rest may trigger exceptions */ ! 464: for(i = 0; i < 6; i++) ! 465: cpu_x86_load_seg_cache(env, i, new_segs[i], 0, 0, 0); ! 466: } ! 467: ! 468: env->ldt.selector = new_ldt & ~4; ! 469: env->ldt.base = 0; ! 470: env->ldt.limit = 0; ! 471: env->ldt.flags = 0; ! 472: ! 473: /* load the LDT */ ! 474: if (new_ldt & 4) ! 475: raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc); ! 476: ! 477: if ((new_ldt & 0xfffc) != 0) { ! 478: dt = &env->gdt; ! 479: index = new_ldt & ~7; ! 480: if ((index + 7) > dt->limit) ! 481: raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc); ! 482: ptr = dt->base + index; ! 483: e1 = ldl_kernel(ptr); ! 484: e2 = ldl_kernel(ptr + 4); ! 485: if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2) ! 486: raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc); ! 487: if (!(e2 & DESC_P_MASK)) ! 488: raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc); ! 489: load_seg_cache_raw_dt(&env->ldt, e1, e2); ! 490: } ! 491: ! 492: /* load the segments */ ! 493: if (!(new_eflags & VM_MASK)) { ! 494: tss_load_seg(R_CS, new_segs[R_CS]); ! 495: tss_load_seg(R_SS, new_segs[R_SS]); ! 496: tss_load_seg(R_ES, new_segs[R_ES]); ! 497: tss_load_seg(R_DS, new_segs[R_DS]); ! 498: tss_load_seg(R_FS, new_segs[R_FS]); ! 499: tss_load_seg(R_GS, new_segs[R_GS]); ! 500: } ! 501: ! 502: /* check that EIP is in the CS segment limits */ ! 503: if (new_eip > env->segs[R_CS].limit) { ! 504: /* XXX: different exception if CALL ? */ ! 505: raise_exception_err(EXCP0D_GPF, 0); ! 506: } ! 507: ! 508: #ifndef CONFIG_USER_ONLY ! 509: /* reset local breakpoints */ ! 510: if (env->dr[7] & 0x55) { ! 511: for (i = 0; i < 4; i++) { ! 512: if (hw_breakpoint_enabled(env->dr[7], i) == 0x1) ! 513: hw_breakpoint_remove(env, i); ! 514: } ! 515: env->dr[7] &= ~0x55; ! 516: } ! 517: #endif ! 518: } ! 519: ! 520: /* check if Port I/O is allowed in TSS */ ! 521: static inline void check_io(int addr, int size) ! 522: { ! 523: int io_offset, val, mask; ! 524: ! 525: /* TSS must be a valid 32 bit one */ ! 526: if (!(env->tr.flags & DESC_P_MASK) || ! 527: ((env->tr.flags >> DESC_TYPE_SHIFT) & 0xf) != 9 || ! 528: env->tr.limit < 103) ! 529: goto fail; ! 530: io_offset = lduw_kernel(env->tr.base + 0x66); ! 531: io_offset += (addr >> 3); ! 532: /* Note: the check needs two bytes */ ! 533: if ((io_offset + 1) > env->tr.limit) ! 534: goto fail; ! 535: val = lduw_kernel(env->tr.base + io_offset); ! 536: val >>= (addr & 7); ! 537: mask = (1 << size) - 1; ! 538: /* all bits must be zero to allow the I/O */ ! 539: if ((val & mask) != 0) { ! 540: fail: ! 541: raise_exception_err(EXCP0D_GPF, 0); ! 542: } ! 543: } ! 544: ! 545: void helper_check_iob(uint32_t t0) ! 546: { ! 547: check_io(t0, 1); ! 548: } ! 549: ! 550: void helper_check_iow(uint32_t t0) ! 551: { ! 552: check_io(t0, 2); ! 553: } ! 554: ! 555: void helper_check_iol(uint32_t t0) ! 556: { ! 557: check_io(t0, 4); ! 558: } ! 559: ! 560: void helper_outb(uint32_t port, uint32_t data) ! 561: { ! 562: cpu_outb(env, port, data & 0xff); ! 563: } ! 564: ! 565: target_ulong helper_inb(uint32_t port) ! 566: { ! 567: return cpu_inb(env, port); ! 568: } ! 569: ! 570: void helper_outw(uint32_t port, uint32_t data) ! 571: { ! 572: cpu_outw(env, port, data & 0xffff); ! 573: } ! 574: ! 575: target_ulong helper_inw(uint32_t port) ! 576: { ! 577: return cpu_inw(env, port); ! 578: } ! 579: ! 580: void helper_outl(uint32_t port, uint32_t data) ! 581: { ! 582: cpu_outl(env, port, data); ! 583: } ! 584: ! 585: target_ulong helper_inl(uint32_t port) ! 586: { ! 587: return cpu_inl(env, port); ! 588: } ! 589: ! 590: static inline unsigned int get_sp_mask(unsigned int e2) ! 591: { ! 592: if (e2 & DESC_B_MASK) ! 593: return 0xffffffff; ! 594: else ! 595: return 0xffff; ! 596: } ! 597: ! 598: #ifdef TARGET_X86_64 ! 599: #define SET_ESP(val, sp_mask)\ ! 600: do {\ ! 601: if ((sp_mask) == 0xffff)\ ! 602: ESP = (ESP & ~0xffff) | ((val) & 0xffff);\ ! 603: else if ((sp_mask) == 0xffffffffLL)\ ! 604: ESP = (uint32_t)(val);\ ! 605: else\ ! 606: ESP = (val);\ ! 607: } while (0) ! 608: #else ! 609: #define SET_ESP(val, sp_mask) ESP = (ESP & ~(sp_mask)) | ((val) & (sp_mask)) ! 610: #endif ! 611: ! 612: /* in 64-bit machines, this can overflow. So this segment addition macro ! 613: * can be used to trim the value to 32-bit whenever needed */ ! 614: #define SEG_ADDL(ssp, sp, sp_mask) ((uint32_t)((ssp) + (sp & (sp_mask)))) ! 615: ! 616: /* XXX: add a is_user flag to have proper security support */ ! 617: #define PUSHW(ssp, sp, sp_mask, val)\ ! 618: {\ ! 619: sp -= 2;\ ! 620: stw_kernel((ssp) + (sp & (sp_mask)), (val));\ ! 621: } ! 622: ! 623: #define PUSHL(ssp, sp, sp_mask, val)\ ! 624: {\ ! 625: sp -= 4;\ ! 626: stl_kernel(SEG_ADDL(ssp, sp, sp_mask), (uint32_t)(val));\ ! 627: } ! 628: ! 629: #define POPW(ssp, sp, sp_mask, val)\ ! 630: {\ ! 631: val = lduw_kernel((ssp) + (sp & (sp_mask)));\ ! 632: sp += 2;\ ! 633: } ! 634: ! 635: #define POPL(ssp, sp, sp_mask, val)\ ! 636: {\ ! 637: val = (uint32_t)ldl_kernel(SEG_ADDL(ssp, sp, sp_mask));\ ! 638: sp += 4;\ ! 639: } ! 640: ! 641: /* protected mode interrupt */ ! 642: static void do_interrupt_protected(int intno, int is_int, int error_code, ! 643: unsigned int next_eip, int is_hw) ! 644: { ! 645: SegmentCache *dt; ! 646: target_ulong ptr, ssp; ! 647: int type, dpl, selector, ss_dpl, cpl; ! 648: int has_error_code, new_stack, shift; ! 649: uint32_t e1, e2, offset, ss = 0, esp, ss_e1 = 0, ss_e2 = 0; ! 650: uint32_t old_eip, sp_mask; ! 651: ! 652: has_error_code = 0; ! 653: if (!is_int && !is_hw) { ! 654: switch(intno) { ! 655: case 8: ! 656: case 10: ! 657: case 11: ! 658: case 12: ! 659: case 13: ! 660: case 14: ! 661: case 17: ! 662: has_error_code = 1; ! 663: break; ! 664: } ! 665: } ! 666: if (is_int) ! 667: old_eip = next_eip; ! 668: else ! 669: old_eip = env->eip; ! 670: ! 671: dt = &env->idt; ! 672: if (intno * 8 + 7 > dt->limit) ! 673: raise_exception_err(EXCP0D_GPF, intno * 8 + 2); ! 674: ptr = dt->base + intno * 8; ! 675: e1 = ldl_kernel(ptr); ! 676: e2 = ldl_kernel(ptr + 4); ! 677: /* check gate type */ ! 678: type = (e2 >> DESC_TYPE_SHIFT) & 0x1f; ! 679: switch(type) { ! 680: case 5: /* task gate */ ! 681: /* must do that check here to return the correct error code */ ! 682: if (!(e2 & DESC_P_MASK)) ! 683: raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2); ! 684: switch_tss(intno * 8, e1, e2, SWITCH_TSS_CALL, old_eip); ! 685: if (has_error_code) { ! 686: int type; ! 687: uint32_t mask; ! 688: /* push the error code */ ! 689: type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf; ! 690: shift = type >> 3; ! 691: if (env->segs[R_SS].flags & DESC_B_MASK) ! 692: mask = 0xffffffff; ! 693: else ! 694: mask = 0xffff; ! 695: esp = (ESP - (2 << shift)) & mask; ! 696: ssp = env->segs[R_SS].base + esp; ! 697: if (shift) ! 698: stl_kernel(ssp, error_code); ! 699: else ! 700: stw_kernel(ssp, error_code); ! 701: SET_ESP(esp, mask); ! 702: } ! 703: return; ! 704: case 6: /* 286 interrupt gate */ ! 705: case 7: /* 286 trap gate */ ! 706: case 14: /* 386 interrupt gate */ ! 707: case 15: /* 386 trap gate */ ! 708: break; ! 709: default: ! 710: raise_exception_err(EXCP0D_GPF, intno * 8 + 2); ! 711: break; ! 712: } ! 713: dpl = (e2 >> DESC_DPL_SHIFT) & 3; ! 714: cpl = env->hflags & HF_CPL_MASK; ! 715: /* check privilege if software int */ ! 716: if (is_int && dpl < cpl) ! 717: raise_exception_err(EXCP0D_GPF, intno * 8 + 2); ! 718: /* check valid bit */ ! 719: if (!(e2 & DESC_P_MASK)) ! 720: raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2); ! 721: selector = e1 >> 16; ! 722: offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff); ! 723: if ((selector & 0xfffc) == 0) ! 724: raise_exception_err(EXCP0D_GPF, 0); ! 725: ! 726: if (load_segment(&e1, &e2, selector) != 0) ! 727: raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ! 728: if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK))) ! 729: raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ! 730: dpl = (e2 >> DESC_DPL_SHIFT) & 3; ! 731: if (dpl > cpl) ! 732: raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ! 733: if (!(e2 & DESC_P_MASK)) ! 734: raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); ! 735: if (!(e2 & DESC_C_MASK) && dpl < cpl) { ! 736: /* to inner privilege */ ! 737: get_ss_esp_from_tss(&ss, &esp, dpl); ! 738: if ((ss & 0xfffc) == 0) ! 739: raise_exception_err(EXCP0A_TSS, ss & 0xfffc); ! 740: if ((ss & 3) != dpl) ! 741: raise_exception_err(EXCP0A_TSS, ss & 0xfffc); ! 742: if (load_segment(&ss_e1, &ss_e2, ss) != 0) ! 743: raise_exception_err(EXCP0A_TSS, ss & 0xfffc); ! 744: ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3; ! 745: if (ss_dpl != dpl) ! 746: raise_exception_err(EXCP0A_TSS, ss & 0xfffc); ! 747: if (!(ss_e2 & DESC_S_MASK) || ! 748: (ss_e2 & DESC_CS_MASK) || ! 749: !(ss_e2 & DESC_W_MASK)) ! 750: raise_exception_err(EXCP0A_TSS, ss & 0xfffc); ! 751: if (!(ss_e2 & DESC_P_MASK)) ! 752: raise_exception_err(EXCP0A_TSS, ss & 0xfffc); ! 753: new_stack = 1; ! 754: sp_mask = get_sp_mask(ss_e2); ! 755: ssp = get_seg_base(ss_e1, ss_e2); ! 756: } else if ((e2 & DESC_C_MASK) || dpl == cpl) { ! 757: /* to same privilege */ ! 758: if (env->eflags & VM_MASK) ! 759: raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ! 760: new_stack = 0; ! 761: sp_mask = get_sp_mask(env->segs[R_SS].flags); ! 762: ssp = env->segs[R_SS].base; ! 763: esp = ESP; ! 764: dpl = cpl; ! 765: } else { ! 766: raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ! 767: new_stack = 0; /* avoid warning */ ! 768: sp_mask = 0; /* avoid warning */ ! 769: ssp = 0; /* avoid warning */ ! 770: esp = 0; /* avoid warning */ ! 771: } ! 772: ! 773: shift = type >> 3; ! 774: ! 775: #if 0 ! 776: /* XXX: check that enough room is available */ ! 777: push_size = 6 + (new_stack << 2) + (has_error_code << 1); ! 778: if (env->eflags & VM_MASK) ! 779: push_size += 8; ! 780: push_size <<= shift; ! 781: #endif ! 782: if (shift == 1) { ! 783: if (new_stack) { ! 784: if (env->eflags & VM_MASK) { ! 785: PUSHL(ssp, esp, sp_mask, env->segs[R_GS].selector); ! 786: PUSHL(ssp, esp, sp_mask, env->segs[R_FS].selector); ! 787: PUSHL(ssp, esp, sp_mask, env->segs[R_DS].selector); ! 788: PUSHL(ssp, esp, sp_mask, env->segs[R_ES].selector); ! 789: } ! 790: PUSHL(ssp, esp, sp_mask, env->segs[R_SS].selector); ! 791: PUSHL(ssp, esp, sp_mask, ESP); ! 792: } ! 793: PUSHL(ssp, esp, sp_mask, compute_eflags()); ! 794: PUSHL(ssp, esp, sp_mask, env->segs[R_CS].selector); ! 795: PUSHL(ssp, esp, sp_mask, old_eip); ! 796: if (has_error_code) { ! 797: PUSHL(ssp, esp, sp_mask, error_code); ! 798: } ! 799: } else { ! 800: if (new_stack) { ! 801: if (env->eflags & VM_MASK) { ! 802: PUSHW(ssp, esp, sp_mask, env->segs[R_GS].selector); ! 803: PUSHW(ssp, esp, sp_mask, env->segs[R_FS].selector); ! 804: PUSHW(ssp, esp, sp_mask, env->segs[R_DS].selector); ! 805: PUSHW(ssp, esp, sp_mask, env->segs[R_ES].selector); ! 806: } ! 807: PUSHW(ssp, esp, sp_mask, env->segs[R_SS].selector); ! 808: PUSHW(ssp, esp, sp_mask, ESP); ! 809: } ! 810: PUSHW(ssp, esp, sp_mask, compute_eflags()); ! 811: PUSHW(ssp, esp, sp_mask, env->segs[R_CS].selector); ! 812: PUSHW(ssp, esp, sp_mask, old_eip); ! 813: if (has_error_code) { ! 814: PUSHW(ssp, esp, sp_mask, error_code); ! 815: } ! 816: } ! 817: ! 818: if (new_stack) { ! 819: if (env->eflags & VM_MASK) { ! 820: cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0, 0); ! 821: cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0, 0); ! 822: cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0, 0); ! 823: cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0, 0); ! 824: } ! 825: ss = (ss & ~3) | dpl; ! 826: cpu_x86_load_seg_cache(env, R_SS, ss, ! 827: ssp, get_seg_limit(ss_e1, ss_e2), ss_e2); ! 828: } ! 829: SET_ESP(esp, sp_mask); ! 830: ! 831: selector = (selector & ~3) | dpl; ! 832: cpu_x86_load_seg_cache(env, R_CS, selector, ! 833: get_seg_base(e1, e2), ! 834: get_seg_limit(e1, e2), ! 835: e2); ! 836: cpu_x86_set_cpl(env, dpl); ! 837: env->eip = offset; ! 838: ! 839: /* interrupt gate clear IF mask */ ! 840: if ((type & 1) == 0) { ! 841: env->eflags &= ~IF_MASK; ! 842: } ! 843: env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK); ! 844: } ! 845: ! 846: #ifdef TARGET_X86_64 ! 847: ! 848: #define PUSHQ(sp, val)\ ! 849: {\ ! 850: sp -= 8;\ ! 851: stq_kernel(sp, (val));\ ! 852: } ! 853: ! 854: #define POPQ(sp, val)\ ! 855: {\ ! 856: val = ldq_kernel(sp);\ ! 857: sp += 8;\ ! 858: } ! 859: ! 860: static inline target_ulong get_rsp_from_tss(int level) ! 861: { ! 862: int index; ! 863: ! 864: #if 0 ! 865: printf("TR: base=" TARGET_FMT_lx " limit=%x\n", ! 866: env->tr.base, env->tr.limit); ! 867: #endif ! 868: ! 869: if (!(env->tr.flags & DESC_P_MASK)) ! 870: cpu_abort(env, "invalid tss"); ! 871: index = 8 * level + 4; ! 872: if ((index + 7) > env->tr.limit) ! 873: raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc); ! 874: return ldq_kernel(env->tr.base + index); ! 875: } ! 876: ! 877: /* 64 bit interrupt */ ! 878: static void do_interrupt64(int intno, int is_int, int error_code, ! 879: target_ulong next_eip, int is_hw) ! 880: { ! 881: SegmentCache *dt; ! 882: target_ulong ptr; ! 883: int type, dpl, selector, cpl, ist; ! 884: int has_error_code, new_stack; ! 885: uint32_t e1, e2, e3, ss; ! 886: target_ulong old_eip, esp, offset; ! 887: ! 888: has_error_code = 0; ! 889: if (!is_int && !is_hw) { ! 890: switch(intno) { ! 891: case 8: ! 892: case 10: ! 893: case 11: ! 894: case 12: ! 895: case 13: ! 896: case 14: ! 897: case 17: ! 898: has_error_code = 1; ! 899: break; ! 900: } ! 901: } ! 902: if (is_int) ! 903: old_eip = next_eip; ! 904: else ! 905: old_eip = env->eip; ! 906: ! 907: dt = &env->idt; ! 908: if (intno * 16 + 15 > dt->limit) ! 909: raise_exception_err(EXCP0D_GPF, intno * 16 + 2); ! 910: ptr = dt->base + intno * 16; ! 911: e1 = ldl_kernel(ptr); ! 912: e2 = ldl_kernel(ptr + 4); ! 913: e3 = ldl_kernel(ptr + 8); ! 914: /* check gate type */ ! 915: type = (e2 >> DESC_TYPE_SHIFT) & 0x1f; ! 916: switch(type) { ! 917: case 14: /* 386 interrupt gate */ ! 918: case 15: /* 386 trap gate */ ! 919: break; ! 920: default: ! 921: raise_exception_err(EXCP0D_GPF, intno * 16 + 2); ! 922: break; ! 923: } ! 924: dpl = (e2 >> DESC_DPL_SHIFT) & 3; ! 925: cpl = env->hflags & HF_CPL_MASK; ! 926: /* check privilege if software int */ ! 927: if (is_int && dpl < cpl) ! 928: raise_exception_err(EXCP0D_GPF, intno * 16 + 2); ! 929: /* check valid bit */ ! 930: if (!(e2 & DESC_P_MASK)) ! 931: raise_exception_err(EXCP0B_NOSEG, intno * 16 + 2); ! 932: selector = e1 >> 16; ! 933: offset = ((target_ulong)e3 << 32) | (e2 & 0xffff0000) | (e1 & 0x0000ffff); ! 934: ist = e2 & 7; ! 935: if ((selector & 0xfffc) == 0) ! 936: raise_exception_err(EXCP0D_GPF, 0); ! 937: ! 938: if (load_segment(&e1, &e2, selector) != 0) ! 939: raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ! 940: if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK))) ! 941: raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ! 942: dpl = (e2 >> DESC_DPL_SHIFT) & 3; ! 943: if (dpl > cpl) ! 944: raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ! 945: if (!(e2 & DESC_P_MASK)) ! 946: raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); ! 947: if (!(e2 & DESC_L_MASK) || (e2 & DESC_B_MASK)) ! 948: raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ! 949: if ((!(e2 & DESC_C_MASK) && dpl < cpl) || ist != 0) { ! 950: /* to inner privilege */ ! 951: if (ist != 0) ! 952: esp = get_rsp_from_tss(ist + 3); ! 953: else ! 954: esp = get_rsp_from_tss(dpl); ! 955: esp &= ~0xfLL; /* align stack */ ! 956: ss = 0; ! 957: new_stack = 1; ! 958: } else if ((e2 & DESC_C_MASK) || dpl == cpl) { ! 959: /* to same privilege */ ! 960: if (env->eflags & VM_MASK) ! 961: raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ! 962: new_stack = 0; ! 963: if (ist != 0) ! 964: esp = get_rsp_from_tss(ist + 3); ! 965: else ! 966: esp = ESP; ! 967: esp &= ~0xfLL; /* align stack */ ! 968: dpl = cpl; ! 969: } else { ! 970: raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ! 971: new_stack = 0; /* avoid warning */ ! 972: esp = 0; /* avoid warning */ ! 973: } ! 974: ! 975: PUSHQ(esp, env->segs[R_SS].selector); ! 976: PUSHQ(esp, ESP); ! 977: PUSHQ(esp, compute_eflags()); ! 978: PUSHQ(esp, env->segs[R_CS].selector); ! 979: PUSHQ(esp, old_eip); ! 980: if (has_error_code) { ! 981: PUSHQ(esp, error_code); ! 982: } ! 983: ! 984: if (new_stack) { ! 985: ss = 0 | dpl; ! 986: cpu_x86_load_seg_cache(env, R_SS, ss, 0, 0, 0); ! 987: } ! 988: ESP = esp; ! 989: ! 990: selector = (selector & ~3) | dpl; ! 991: cpu_x86_load_seg_cache(env, R_CS, selector, ! 992: get_seg_base(e1, e2), ! 993: get_seg_limit(e1, e2), ! 994: e2); ! 995: cpu_x86_set_cpl(env, dpl); ! 996: env->eip = offset; ! 997: ! 998: /* interrupt gate clear IF mask */ ! 999: if ((type & 1) == 0) { ! 1000: env->eflags &= ~IF_MASK; ! 1001: } ! 1002: env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK); ! 1003: } ! 1004: #endif ! 1005: ! 1006: #ifdef TARGET_X86_64 ! 1007: #if defined(CONFIG_USER_ONLY) ! 1008: void helper_syscall(int next_eip_addend) ! 1009: { ! 1010: env->exception_index = EXCP_SYSCALL; ! 1011: env->exception_next_eip = env->eip + next_eip_addend; ! 1012: cpu_loop_exit(); ! 1013: } ! 1014: #else ! 1015: void helper_syscall(int next_eip_addend) ! 1016: { ! 1017: int selector; ! 1018: ! 1019: if (!(env->efer & MSR_EFER_SCE)) { ! 1020: raise_exception_err(EXCP06_ILLOP, 0); ! 1021: } ! 1022: selector = (env->star >> 32) & 0xffff; ! 1023: if (env->hflags & HF_LMA_MASK) { ! 1024: int code64; ! 1025: ! 1026: ECX = env->eip + next_eip_addend; ! 1027: env->regs[11] = compute_eflags(); ! 1028: ! 1029: code64 = env->hflags & HF_CS64_MASK; ! 1030: ! 1031: cpu_x86_set_cpl(env, 0); ! 1032: cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc, ! 1033: 0, 0xffffffff, ! 1034: DESC_G_MASK | DESC_P_MASK | ! 1035: DESC_S_MASK | ! 1036: DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK); ! 1037: cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc, ! 1038: 0, 0xffffffff, ! 1039: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | ! 1040: DESC_S_MASK | ! 1041: DESC_W_MASK | DESC_A_MASK); ! 1042: env->eflags &= ~env->fmask; ! 1043: load_eflags(env->eflags, 0); ! 1044: if (code64) ! 1045: env->eip = env->lstar; ! 1046: else ! 1047: env->eip = env->cstar; ! 1048: } else { ! 1049: ECX = (uint32_t)(env->eip + next_eip_addend); ! 1050: ! 1051: cpu_x86_set_cpl(env, 0); ! 1052: cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc, ! 1053: 0, 0xffffffff, ! 1054: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | ! 1055: DESC_S_MASK | ! 1056: DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); ! 1057: cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc, ! 1058: 0, 0xffffffff, ! 1059: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | ! 1060: DESC_S_MASK | ! 1061: DESC_W_MASK | DESC_A_MASK); ! 1062: env->eflags &= ~(IF_MASK | RF_MASK | VM_MASK); ! 1063: env->eip = (uint32_t)env->star; ! 1064: } ! 1065: } ! 1066: #endif ! 1067: #endif ! 1068: ! 1069: #ifdef TARGET_X86_64 ! 1070: void helper_sysret(int dflag) ! 1071: { ! 1072: int cpl, selector; ! 1073: ! 1074: if (!(env->efer & MSR_EFER_SCE)) { ! 1075: raise_exception_err(EXCP06_ILLOP, 0); ! 1076: } ! 1077: cpl = env->hflags & HF_CPL_MASK; ! 1078: if (!(env->cr[0] & CR0_PE_MASK) || cpl != 0) { ! 1079: raise_exception_err(EXCP0D_GPF, 0); ! 1080: } ! 1081: selector = (env->star >> 48) & 0xffff; ! 1082: if (env->hflags & HF_LMA_MASK) { ! 1083: if (dflag == 2) { ! 1084: cpu_x86_load_seg_cache(env, R_CS, (selector + 16) | 3, ! 1085: 0, 0xffffffff, ! 1086: DESC_G_MASK | DESC_P_MASK | ! 1087: DESC_S_MASK | (3 << DESC_DPL_SHIFT) | ! 1088: DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | ! 1089: DESC_L_MASK); ! 1090: env->eip = ECX; ! 1091: } else { ! 1092: cpu_x86_load_seg_cache(env, R_CS, selector | 3, ! 1093: 0, 0xffffffff, ! 1094: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | ! 1095: DESC_S_MASK | (3 << DESC_DPL_SHIFT) | ! 1096: DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); ! 1097: env->eip = (uint32_t)ECX; ! 1098: } ! 1099: cpu_x86_load_seg_cache(env, R_SS, selector + 8, ! 1100: 0, 0xffffffff, ! 1101: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | ! 1102: DESC_S_MASK | (3 << DESC_DPL_SHIFT) | ! 1103: DESC_W_MASK | DESC_A_MASK); ! 1104: load_eflags((uint32_t)(env->regs[11]), TF_MASK | AC_MASK | ID_MASK | ! 1105: IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | NT_MASK); ! 1106: cpu_x86_set_cpl(env, 3); ! 1107: } else { ! 1108: cpu_x86_load_seg_cache(env, R_CS, selector | 3, ! 1109: 0, 0xffffffff, ! 1110: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | ! 1111: DESC_S_MASK | (3 << DESC_DPL_SHIFT) | ! 1112: DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); ! 1113: env->eip = (uint32_t)ECX; ! 1114: cpu_x86_load_seg_cache(env, R_SS, selector + 8, ! 1115: 0, 0xffffffff, ! 1116: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | ! 1117: DESC_S_MASK | (3 << DESC_DPL_SHIFT) | ! 1118: DESC_W_MASK | DESC_A_MASK); ! 1119: env->eflags |= IF_MASK; ! 1120: cpu_x86_set_cpl(env, 3); ! 1121: } ! 1122: #ifdef USE_KQEMU ! 1123: if (kqemu_is_ok(env)) { ! 1124: if (env->hflags & HF_LMA_MASK) ! 1125: CC_OP = CC_OP_EFLAGS; ! 1126: env->exception_index = -1; ! 1127: cpu_loop_exit(); ! 1128: } ! 1129: #endif ! 1130: } ! 1131: #endif ! 1132: ! 1133: /* real mode interrupt */ ! 1134: static void do_interrupt_real(int intno, int is_int, int error_code, ! 1135: unsigned int next_eip) ! 1136: { ! 1137: SegmentCache *dt; ! 1138: target_ulong ptr, ssp; ! 1139: int selector; ! 1140: uint32_t offset, esp; ! 1141: uint32_t old_cs, old_eip; ! 1142: ! 1143: /* real mode (simpler !) */ ! 1144: dt = &env->idt; ! 1145: if (intno * 4 + 3 > dt->limit) ! 1146: raise_exception_err(EXCP0D_GPF, intno * 8 + 2); ! 1147: ptr = dt->base + intno * 4; ! 1148: offset = lduw_kernel(ptr); ! 1149: selector = lduw_kernel(ptr + 2); ! 1150: esp = ESP; ! 1151: ssp = env->segs[R_SS].base; ! 1152: if (is_int) ! 1153: old_eip = next_eip; ! 1154: else ! 1155: old_eip = env->eip; ! 1156: old_cs = env->segs[R_CS].selector; ! 1157: /* XXX: use SS segment size ? */ ! 1158: PUSHW(ssp, esp, 0xffff, compute_eflags()); ! 1159: PUSHW(ssp, esp, 0xffff, old_cs); ! 1160: PUSHW(ssp, esp, 0xffff, old_eip); ! 1161: ! 1162: /* update processor state */ ! 1163: ESP = (ESP & ~0xffff) | (esp & 0xffff); ! 1164: env->eip = offset; ! 1165: env->segs[R_CS].selector = selector; ! 1166: env->segs[R_CS].base = (selector << 4); ! 1167: env->eflags &= ~(IF_MASK | TF_MASK | AC_MASK | RF_MASK); ! 1168: } ! 1169: ! 1170: /* fake user mode interrupt */ ! 1171: void do_interrupt_user(int intno, int is_int, int error_code, ! 1172: target_ulong next_eip) ! 1173: { ! 1174: SegmentCache *dt; ! 1175: target_ulong ptr; ! 1176: int dpl, cpl, shift; ! 1177: uint32_t e2; ! 1178: ! 1179: dt = &env->idt; ! 1180: if (env->hflags & HF_LMA_MASK) { ! 1181: shift = 4; ! 1182: } else { ! 1183: shift = 3; ! 1184: } ! 1185: ptr = dt->base + (intno << shift); ! 1186: e2 = ldl_kernel(ptr + 4); ! 1187: ! 1188: dpl = (e2 >> DESC_DPL_SHIFT) & 3; ! 1189: cpl = env->hflags & HF_CPL_MASK; ! 1190: /* check privilege if software int */ ! 1191: if (is_int && dpl < cpl) ! 1192: raise_exception_err(EXCP0D_GPF, (intno << shift) + 2); ! 1193: ! 1194: /* Since we emulate only user space, we cannot do more than ! 1195: exiting the emulation with the suitable exception and error ! 1196: code */ ! 1197: if (is_int) ! 1198: EIP = next_eip; ! 1199: } ! 1200: ! 1201: /* ! 1202: * Begin execution of an interruption. is_int is TRUE if coming from ! 1203: * the int instruction. next_eip is the EIP value AFTER the interrupt ! 1204: * instruction. It is only relevant if is_int is TRUE. ! 1205: */ ! 1206: void do_interrupt(int intno, int is_int, int error_code, ! 1207: target_ulong next_eip, int is_hw) ! 1208: { ! 1209: if (qemu_loglevel_mask(CPU_LOG_INT)) { ! 1210: if ((env->cr[0] & CR0_PE_MASK)) { ! 1211: static int count; ! 1212: qemu_log("%6d: v=%02x e=%04x i=%d cpl=%d IP=%04x:" TARGET_FMT_lx " pc=" TARGET_FMT_lx " SP=%04x:" TARGET_FMT_lx, ! 1213: count, intno, error_code, is_int, ! 1214: env->hflags & HF_CPL_MASK, ! 1215: env->segs[R_CS].selector, EIP, ! 1216: (int)env->segs[R_CS].base + EIP, ! 1217: env->segs[R_SS].selector, ESP); ! 1218: if (intno == 0x0e) { ! 1219: qemu_log(" CR2=" TARGET_FMT_lx, env->cr[2]); ! 1220: } else { ! 1221: qemu_log(" EAX=" TARGET_FMT_lx, EAX); ! 1222: } ! 1223: qemu_log("\n"); ! 1224: log_cpu_state(env, X86_DUMP_CCOP); ! 1225: #if 0 ! 1226: { ! 1227: int i; ! 1228: uint8_t *ptr; ! 1229: qemu_log(" code="); ! 1230: ptr = env->segs[R_CS].base + env->eip; ! 1231: for(i = 0; i < 16; i++) { ! 1232: qemu_log(" %02x", ldub(ptr + i)); ! 1233: } ! 1234: qemu_log("\n"); ! 1235: } ! 1236: #endif ! 1237: count++; ! 1238: } ! 1239: } ! 1240: if (env->cr[0] & CR0_PE_MASK) { ! 1241: #ifdef TARGET_X86_64 ! 1242: if (env->hflags & HF_LMA_MASK) { ! 1243: do_interrupt64(intno, is_int, error_code, next_eip, is_hw); ! 1244: } else ! 1245: #endif ! 1246: { ! 1247: do_interrupt_protected(intno, is_int, error_code, next_eip, is_hw); ! 1248: } ! 1249: } else { ! 1250: do_interrupt_real(intno, is_int, error_code, next_eip); ! 1251: } ! 1252: } ! 1253: ! 1254: /* This should come from sysemu.h - if we could include it here... */ ! 1255: void qemu_system_reset_request(void); ! 1256: ! 1257: /* ! 1258: * Check nested exceptions and change to double or triple fault if ! 1259: * needed. It should only be called, if this is not an interrupt. ! 1260: * Returns the new exception number. ! 1261: */ ! 1262: static int check_exception(int intno, int *error_code) ! 1263: { ! 1264: int first_contributory = env->old_exception == 0 || ! 1265: (env->old_exception >= 10 && ! 1266: env->old_exception <= 13); ! 1267: int second_contributory = intno == 0 || ! 1268: (intno >= 10 && intno <= 13); ! 1269: ! 1270: qemu_log_mask(CPU_LOG_INT, "check_exception old: 0x%x new 0x%x\n", ! 1271: env->old_exception, intno); ! 1272: ! 1273: #if !defined(CONFIG_USER_ONLY) ! 1274: if (env->old_exception == EXCP08_DBLE) { ! 1275: if (env->hflags & HF_SVMI_MASK) ! 1276: helper_vmexit(SVM_EXIT_SHUTDOWN, 0); /* does not return */ ! 1277: ! 1278: qemu_log_mask(CPU_LOG_RESET, "Triple fault\n"); ! 1279: ! 1280: qemu_system_reset_request(); ! 1281: return EXCP_HLT; ! 1282: } ! 1283: #endif ! 1284: ! 1285: if ((first_contributory && second_contributory) ! 1286: || (env->old_exception == EXCP0E_PAGE && ! 1287: (second_contributory || (intno == EXCP0E_PAGE)))) { ! 1288: intno = EXCP08_DBLE; ! 1289: *error_code = 0; ! 1290: } ! 1291: ! 1292: if (second_contributory || (intno == EXCP0E_PAGE) || ! 1293: (intno == EXCP08_DBLE)) ! 1294: env->old_exception = intno; ! 1295: ! 1296: return intno; ! 1297: } ! 1298: ! 1299: /* ! 1300: * Signal an interruption. It is executed in the main CPU loop. ! 1301: * is_int is TRUE if coming from the int instruction. next_eip is the ! 1302: * EIP value AFTER the interrupt instruction. It is only relevant if ! 1303: * is_int is TRUE. ! 1304: */ ! 1305: static void QEMU_NORETURN raise_interrupt(int intno, int is_int, int error_code, ! 1306: int next_eip_addend) ! 1307: { ! 1308: if (!is_int) { ! 1309: helper_svm_check_intercept_param(SVM_EXIT_EXCP_BASE + intno, error_code); ! 1310: intno = check_exception(intno, &error_code); ! 1311: } else { ! 1312: helper_svm_check_intercept_param(SVM_EXIT_SWINT, 0); ! 1313: } ! 1314: ! 1315: env->exception_index = intno; ! 1316: env->error_code = error_code; ! 1317: env->exception_is_int = is_int; ! 1318: env->exception_next_eip = env->eip + next_eip_addend; ! 1319: cpu_loop_exit(); ! 1320: } ! 1321: ! 1322: /* shortcuts to generate exceptions */ ! 1323: ! 1324: void raise_exception_err(int exception_index, int error_code) ! 1325: { ! 1326: raise_interrupt(exception_index, 0, error_code, 0); ! 1327: } ! 1328: ! 1329: void raise_exception(int exception_index) ! 1330: { ! 1331: raise_interrupt(exception_index, 0, 0, 0); ! 1332: } ! 1333: ! 1334: /* SMM support */ ! 1335: ! 1336: #if defined(CONFIG_USER_ONLY) ! 1337: ! 1338: void do_smm_enter(void) ! 1339: { ! 1340: } ! 1341: ! 1342: void helper_rsm(void) ! 1343: { ! 1344: } ! 1345: ! 1346: #else ! 1347: ! 1348: #ifdef TARGET_X86_64 ! 1349: #define SMM_REVISION_ID 0x00020064 ! 1350: #else ! 1351: #define SMM_REVISION_ID 0x00020000 ! 1352: #endif ! 1353: ! 1354: void do_smm_enter(void) ! 1355: { ! 1356: target_ulong sm_state; ! 1357: SegmentCache *dt; ! 1358: int i, offset; ! 1359: ! 1360: qemu_log_mask(CPU_LOG_INT, "SMM: enter\n"); ! 1361: log_cpu_state_mask(CPU_LOG_INT, env, X86_DUMP_CCOP); ! 1362: ! 1363: env->hflags |= HF_SMM_MASK; ! 1364: cpu_smm_update(env); ! 1365: ! 1366: sm_state = env->smbase + 0x8000; ! 1367: ! 1368: #ifdef TARGET_X86_64 ! 1369: for(i = 0; i < 6; i++) { ! 1370: dt = &env->segs[i]; ! 1371: offset = 0x7e00 + i * 16; ! 1372: stw_phys(sm_state + offset, dt->selector); ! 1373: stw_phys(sm_state + offset + 2, (dt->flags >> 8) & 0xf0ff); ! 1374: stl_phys(sm_state + offset + 4, dt->limit); ! 1375: stq_phys(sm_state + offset + 8, dt->base); ! 1376: } ! 1377: ! 1378: stq_phys(sm_state + 0x7e68, env->gdt.base); ! 1379: stl_phys(sm_state + 0x7e64, env->gdt.limit); ! 1380: ! 1381: stw_phys(sm_state + 0x7e70, env->ldt.selector); ! 1382: stq_phys(sm_state + 0x7e78, env->ldt.base); ! 1383: stl_phys(sm_state + 0x7e74, env->ldt.limit); ! 1384: stw_phys(sm_state + 0x7e72, (env->ldt.flags >> 8) & 0xf0ff); ! 1385: ! 1386: stq_phys(sm_state + 0x7e88, env->idt.base); ! 1387: stl_phys(sm_state + 0x7e84, env->idt.limit); ! 1388: ! 1389: stw_phys(sm_state + 0x7e90, env->tr.selector); ! 1390: stq_phys(sm_state + 0x7e98, env->tr.base); ! 1391: stl_phys(sm_state + 0x7e94, env->tr.limit); ! 1392: stw_phys(sm_state + 0x7e92, (env->tr.flags >> 8) & 0xf0ff); ! 1393: ! 1394: stq_phys(sm_state + 0x7ed0, env->efer); ! 1395: ! 1396: stq_phys(sm_state + 0x7ff8, EAX); ! 1397: stq_phys(sm_state + 0x7ff0, ECX); ! 1398: stq_phys(sm_state + 0x7fe8, EDX); ! 1399: stq_phys(sm_state + 0x7fe0, EBX); ! 1400: stq_phys(sm_state + 0x7fd8, ESP); ! 1401: stq_phys(sm_state + 0x7fd0, EBP); ! 1402: stq_phys(sm_state + 0x7fc8, ESI); ! 1403: stq_phys(sm_state + 0x7fc0, EDI); ! 1404: for(i = 8; i < 16; i++) ! 1405: stq_phys(sm_state + 0x7ff8 - i * 8, env->regs[i]); ! 1406: stq_phys(sm_state + 0x7f78, env->eip); ! 1407: stl_phys(sm_state + 0x7f70, compute_eflags()); ! 1408: stl_phys(sm_state + 0x7f68, env->dr[6]); ! 1409: stl_phys(sm_state + 0x7f60, env->dr[7]); ! 1410: ! 1411: stl_phys(sm_state + 0x7f48, env->cr[4]); ! 1412: stl_phys(sm_state + 0x7f50, env->cr[3]); ! 1413: stl_phys(sm_state + 0x7f58, env->cr[0]); ! 1414: ! 1415: stl_phys(sm_state + 0x7efc, SMM_REVISION_ID); ! 1416: stl_phys(sm_state + 0x7f00, env->smbase); ! 1417: #else ! 1418: stl_phys(sm_state + 0x7ffc, env->cr[0]); ! 1419: stl_phys(sm_state + 0x7ff8, env->cr[3]); ! 1420: stl_phys(sm_state + 0x7ff4, compute_eflags()); ! 1421: stl_phys(sm_state + 0x7ff0, env->eip); ! 1422: stl_phys(sm_state + 0x7fec, EDI); ! 1423: stl_phys(sm_state + 0x7fe8, ESI); ! 1424: stl_phys(sm_state + 0x7fe4, EBP); ! 1425: stl_phys(sm_state + 0x7fe0, ESP); ! 1426: stl_phys(sm_state + 0x7fdc, EBX); ! 1427: stl_phys(sm_state + 0x7fd8, EDX); ! 1428: stl_phys(sm_state + 0x7fd4, ECX); ! 1429: stl_phys(sm_state + 0x7fd0, EAX); ! 1430: stl_phys(sm_state + 0x7fcc, env->dr[6]); ! 1431: stl_phys(sm_state + 0x7fc8, env->dr[7]); ! 1432: ! 1433: stl_phys(sm_state + 0x7fc4, env->tr.selector); ! 1434: stl_phys(sm_state + 0x7f64, env->tr.base); ! 1435: stl_phys(sm_state + 0x7f60, env->tr.limit); ! 1436: stl_phys(sm_state + 0x7f5c, (env->tr.flags >> 8) & 0xf0ff); ! 1437: ! 1438: stl_phys(sm_state + 0x7fc0, env->ldt.selector); ! 1439: stl_phys(sm_state + 0x7f80, env->ldt.base); ! 1440: stl_phys(sm_state + 0x7f7c, env->ldt.limit); ! 1441: stl_phys(sm_state + 0x7f78, (env->ldt.flags >> 8) & 0xf0ff); ! 1442: ! 1443: stl_phys(sm_state + 0x7f74, env->gdt.base); ! 1444: stl_phys(sm_state + 0x7f70, env->gdt.limit); ! 1445: ! 1446: stl_phys(sm_state + 0x7f58, env->idt.base); ! 1447: stl_phys(sm_state + 0x7f54, env->idt.limit); ! 1448: ! 1449: for(i = 0; i < 6; i++) { ! 1450: dt = &env->segs[i]; ! 1451: if (i < 3) ! 1452: offset = 0x7f84 + i * 12; ! 1453: else ! 1454: offset = 0x7f2c + (i - 3) * 12; ! 1455: stl_phys(sm_state + 0x7fa8 + i * 4, dt->selector); ! 1456: stl_phys(sm_state + offset + 8, dt->base); ! 1457: stl_phys(sm_state + offset + 4, dt->limit); ! 1458: stl_phys(sm_state + offset, (dt->flags >> 8) & 0xf0ff); ! 1459: } ! 1460: stl_phys(sm_state + 0x7f14, env->cr[4]); ! 1461: ! 1462: stl_phys(sm_state + 0x7efc, SMM_REVISION_ID); ! 1463: stl_phys(sm_state + 0x7ef8, env->smbase); ! 1464: #endif ! 1465: /* init SMM cpu state */ ! 1466: ! 1467: #ifdef TARGET_X86_64 ! 1468: cpu_load_efer(env, 0); ! 1469: #endif ! 1470: load_eflags(0, ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK)); ! 1471: env->eip = 0x00008000; ! 1472: cpu_x86_load_seg_cache(env, R_CS, (env->smbase >> 4) & 0xffff, env->smbase, ! 1473: 0xffffffff, 0); ! 1474: cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0xffffffff, 0); ! 1475: cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0xffffffff, 0); ! 1476: cpu_x86_load_seg_cache(env, R_SS, 0, 0, 0xffffffff, 0); ! 1477: cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0xffffffff, 0); ! 1478: cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0xffffffff, 0); ! 1479: ! 1480: cpu_x86_update_cr0(env, ! 1481: env->cr[0] & ~(CR0_PE_MASK | CR0_EM_MASK | CR0_TS_MASK | CR0_PG_MASK)); ! 1482: cpu_x86_update_cr4(env, 0); ! 1483: env->dr[7] = 0x00000400; ! 1484: CC_OP = CC_OP_EFLAGS; ! 1485: } ! 1486: ! 1487: void helper_rsm(void) ! 1488: { ! 1489: target_ulong sm_state; ! 1490: int i, offset; ! 1491: uint32_t val; ! 1492: ! 1493: sm_state = env->smbase + 0x8000; ! 1494: #ifdef TARGET_X86_64 ! 1495: cpu_load_efer(env, ldq_phys(sm_state + 0x7ed0)); ! 1496: ! 1497: for(i = 0; i < 6; i++) { ! 1498: offset = 0x7e00 + i * 16; ! 1499: cpu_x86_load_seg_cache(env, i, ! 1500: lduw_phys(sm_state + offset), ! 1501: ldq_phys(sm_state + offset + 8), ! 1502: ldl_phys(sm_state + offset + 4), ! 1503: (lduw_phys(sm_state + offset + 2) & 0xf0ff) << 8); ! 1504: } ! 1505: ! 1506: env->gdt.base = ldq_phys(sm_state + 0x7e68); ! 1507: env->gdt.limit = ldl_phys(sm_state + 0x7e64); ! 1508: ! 1509: env->ldt.selector = lduw_phys(sm_state + 0x7e70); ! 1510: env->ldt.base = ldq_phys(sm_state + 0x7e78); ! 1511: env->ldt.limit = ldl_phys(sm_state + 0x7e74); ! 1512: env->ldt.flags = (lduw_phys(sm_state + 0x7e72) & 0xf0ff) << 8; ! 1513: ! 1514: env->idt.base = ldq_phys(sm_state + 0x7e88); ! 1515: env->idt.limit = ldl_phys(sm_state + 0x7e84); ! 1516: ! 1517: env->tr.selector = lduw_phys(sm_state + 0x7e90); ! 1518: env->tr.base = ldq_phys(sm_state + 0x7e98); ! 1519: env->tr.limit = ldl_phys(sm_state + 0x7e94); ! 1520: env->tr.flags = (lduw_phys(sm_state + 0x7e92) & 0xf0ff) << 8; ! 1521: ! 1522: EAX = ldq_phys(sm_state + 0x7ff8); ! 1523: ECX = ldq_phys(sm_state + 0x7ff0); ! 1524: EDX = ldq_phys(sm_state + 0x7fe8); ! 1525: EBX = ldq_phys(sm_state + 0x7fe0); ! 1526: ESP = ldq_phys(sm_state + 0x7fd8); ! 1527: EBP = ldq_phys(sm_state + 0x7fd0); ! 1528: ESI = ldq_phys(sm_state + 0x7fc8); ! 1529: EDI = ldq_phys(sm_state + 0x7fc0); ! 1530: for(i = 8; i < 16; i++) ! 1531: env->regs[i] = ldq_phys(sm_state + 0x7ff8 - i * 8); ! 1532: env->eip = ldq_phys(sm_state + 0x7f78); ! 1533: load_eflags(ldl_phys(sm_state + 0x7f70), ! 1534: ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK)); ! 1535: env->dr[6] = ldl_phys(sm_state + 0x7f68); ! 1536: env->dr[7] = ldl_phys(sm_state + 0x7f60); ! 1537: ! 1538: cpu_x86_update_cr4(env, ldl_phys(sm_state + 0x7f48)); ! 1539: cpu_x86_update_cr3(env, ldl_phys(sm_state + 0x7f50)); ! 1540: cpu_x86_update_cr0(env, ldl_phys(sm_state + 0x7f58)); ! 1541: ! 1542: val = ldl_phys(sm_state + 0x7efc); /* revision ID */ ! 1543: if (val & 0x20000) { ! 1544: env->smbase = ldl_phys(sm_state + 0x7f00) & ~0x7fff; ! 1545: } ! 1546: #else ! 1547: cpu_x86_update_cr0(env, ldl_phys(sm_state + 0x7ffc)); ! 1548: cpu_x86_update_cr3(env, ldl_phys(sm_state + 0x7ff8)); ! 1549: load_eflags(ldl_phys(sm_state + 0x7ff4), ! 1550: ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK)); ! 1551: env->eip = ldl_phys(sm_state + 0x7ff0); ! 1552: EDI = ldl_phys(sm_state + 0x7fec); ! 1553: ESI = ldl_phys(sm_state + 0x7fe8); ! 1554: EBP = ldl_phys(sm_state + 0x7fe4); ! 1555: ESP = ldl_phys(sm_state + 0x7fe0); ! 1556: EBX = ldl_phys(sm_state + 0x7fdc); ! 1557: EDX = ldl_phys(sm_state + 0x7fd8); ! 1558: ECX = ldl_phys(sm_state + 0x7fd4); ! 1559: EAX = ldl_phys(sm_state + 0x7fd0); ! 1560: env->dr[6] = ldl_phys(sm_state + 0x7fcc); ! 1561: env->dr[7] = ldl_phys(sm_state + 0x7fc8); ! 1562: ! 1563: env->tr.selector = ldl_phys(sm_state + 0x7fc4) & 0xffff; ! 1564: env->tr.base = ldl_phys(sm_state + 0x7f64); ! 1565: env->tr.limit = ldl_phys(sm_state + 0x7f60); ! 1566: env->tr.flags = (ldl_phys(sm_state + 0x7f5c) & 0xf0ff) << 8; ! 1567: ! 1568: env->ldt.selector = ldl_phys(sm_state + 0x7fc0) & 0xffff; ! 1569: env->ldt.base = ldl_phys(sm_state + 0x7f80); ! 1570: env->ldt.limit = ldl_phys(sm_state + 0x7f7c); ! 1571: env->ldt.flags = (ldl_phys(sm_state + 0x7f78) & 0xf0ff) << 8; ! 1572: ! 1573: env->gdt.base = ldl_phys(sm_state + 0x7f74); ! 1574: env->gdt.limit = ldl_phys(sm_state + 0x7f70); ! 1575: ! 1576: env->idt.base = ldl_phys(sm_state + 0x7f58); ! 1577: env->idt.limit = ldl_phys(sm_state + 0x7f54); ! 1578: ! 1579: for(i = 0; i < 6; i++) { ! 1580: if (i < 3) ! 1581: offset = 0x7f84 + i * 12; ! 1582: else ! 1583: offset = 0x7f2c + (i - 3) * 12; ! 1584: cpu_x86_load_seg_cache(env, i, ! 1585: ldl_phys(sm_state + 0x7fa8 + i * 4) & 0xffff, ! 1586: ldl_phys(sm_state + offset + 8), ! 1587: ldl_phys(sm_state + offset + 4), ! 1588: (ldl_phys(sm_state + offset) & 0xf0ff) << 8); ! 1589: } ! 1590: cpu_x86_update_cr4(env, ldl_phys(sm_state + 0x7f14)); ! 1591: ! 1592: val = ldl_phys(sm_state + 0x7efc); /* revision ID */ ! 1593: if (val & 0x20000) { ! 1594: env->smbase = ldl_phys(sm_state + 0x7ef8) & ~0x7fff; ! 1595: } ! 1596: #endif ! 1597: CC_OP = CC_OP_EFLAGS; ! 1598: env->hflags &= ~HF_SMM_MASK; ! 1599: cpu_smm_update(env); ! 1600: ! 1601: qemu_log_mask(CPU_LOG_INT, "SMM: after RSM\n"); ! 1602: log_cpu_state_mask(CPU_LOG_INT, env, X86_DUMP_CCOP); ! 1603: } ! 1604: ! 1605: #endif /* !CONFIG_USER_ONLY */ ! 1606: ! 1607: ! 1608: /* division, flags are undefined */ ! 1609: ! 1610: void helper_divb_AL(target_ulong t0) ! 1611: { ! 1612: unsigned int num, den, q, r; ! 1613: ! 1614: num = (EAX & 0xffff); ! 1615: den = (t0 & 0xff); ! 1616: if (den == 0) { ! 1617: raise_exception(EXCP00_DIVZ); ! 1618: } ! 1619: q = (num / den); ! 1620: if (q > 0xff) ! 1621: raise_exception(EXCP00_DIVZ); ! 1622: q &= 0xff; ! 1623: r = (num % den) & 0xff; ! 1624: EAX = (EAX & ~0xffff) | (r << 8) | q; ! 1625: } ! 1626: ! 1627: void helper_idivb_AL(target_ulong t0) ! 1628: { ! 1629: int num, den, q, r; ! 1630: ! 1631: num = (int16_t)EAX; ! 1632: den = (int8_t)t0; ! 1633: if (den == 0) { ! 1634: raise_exception(EXCP00_DIVZ); ! 1635: } ! 1636: q = (num / den); ! 1637: if (q != (int8_t)q) ! 1638: raise_exception(EXCP00_DIVZ); ! 1639: q &= 0xff; ! 1640: r = (num % den) & 0xff; ! 1641: EAX = (EAX & ~0xffff) | (r << 8) | q; ! 1642: } ! 1643: ! 1644: void helper_divw_AX(target_ulong t0) ! 1645: { ! 1646: unsigned int num, den, q, r; ! 1647: ! 1648: num = (EAX & 0xffff) | ((EDX & 0xffff) << 16); ! 1649: den = (t0 & 0xffff); ! 1650: if (den == 0) { ! 1651: raise_exception(EXCP00_DIVZ); ! 1652: } ! 1653: q = (num / den); ! 1654: if (q > 0xffff) ! 1655: raise_exception(EXCP00_DIVZ); ! 1656: q &= 0xffff; ! 1657: r = (num % den) & 0xffff; ! 1658: EAX = (EAX & ~0xffff) | q; ! 1659: EDX = (EDX & ~0xffff) | r; ! 1660: } ! 1661: ! 1662: void helper_idivw_AX(target_ulong t0) ! 1663: { ! 1664: int num, den, q, r; ! 1665: ! 1666: num = (EAX & 0xffff) | ((EDX & 0xffff) << 16); ! 1667: den = (int16_t)t0; ! 1668: if (den == 0) { ! 1669: raise_exception(EXCP00_DIVZ); ! 1670: } ! 1671: q = (num / den); ! 1672: if (q != (int16_t)q) ! 1673: raise_exception(EXCP00_DIVZ); ! 1674: q &= 0xffff; ! 1675: r = (num % den) & 0xffff; ! 1676: EAX = (EAX & ~0xffff) | q; ! 1677: EDX = (EDX & ~0xffff) | r; ! 1678: } ! 1679: ! 1680: void helper_divl_EAX(target_ulong t0) ! 1681: { ! 1682: unsigned int den, r; ! 1683: uint64_t num, q; ! 1684: ! 1685: num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32); ! 1686: den = t0; ! 1687: if (den == 0) { ! 1688: raise_exception(EXCP00_DIVZ); ! 1689: } ! 1690: q = (num / den); ! 1691: r = (num % den); ! 1692: if (q > 0xffffffff) ! 1693: raise_exception(EXCP00_DIVZ); ! 1694: EAX = (uint32_t)q; ! 1695: EDX = (uint32_t)r; ! 1696: } ! 1697: ! 1698: void helper_idivl_EAX(target_ulong t0) ! 1699: { ! 1700: int den, r; ! 1701: int64_t num, q; ! 1702: ! 1703: num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32); ! 1704: den = t0; ! 1705: if (den == 0) { ! 1706: raise_exception(EXCP00_DIVZ); ! 1707: } ! 1708: q = (num / den); ! 1709: r = (num % den); ! 1710: if (q != (int32_t)q) ! 1711: raise_exception(EXCP00_DIVZ); ! 1712: EAX = (uint32_t)q; ! 1713: EDX = (uint32_t)r; ! 1714: } ! 1715: ! 1716: /* bcd */ ! 1717: ! 1718: /* XXX: exception */ ! 1719: void helper_aam(int base) ! 1720: { ! 1721: int al, ah; ! 1722: al = EAX & 0xff; ! 1723: ah = al / base; ! 1724: al = al % base; ! 1725: EAX = (EAX & ~0xffff) | al | (ah << 8); ! 1726: CC_DST = al; ! 1727: } ! 1728: ! 1729: void helper_aad(int base) ! 1730: { ! 1731: int al, ah; ! 1732: al = EAX & 0xff; ! 1733: ah = (EAX >> 8) & 0xff; ! 1734: al = ((ah * base) + al) & 0xff; ! 1735: EAX = (EAX & ~0xffff) | al; ! 1736: CC_DST = al; ! 1737: } ! 1738: ! 1739: void helper_aaa(void) ! 1740: { ! 1741: int icarry; ! 1742: int al, ah, af; ! 1743: int eflags; ! 1744: ! 1745: eflags = helper_cc_compute_all(CC_OP); ! 1746: af = eflags & CC_A; ! 1747: al = EAX & 0xff; ! 1748: ah = (EAX >> 8) & 0xff; ! 1749: ! 1750: icarry = (al > 0xf9); ! 1751: if (((al & 0x0f) > 9 ) || af) { ! 1752: al = (al + 6) & 0x0f; ! 1753: ah = (ah + 1 + icarry) & 0xff; ! 1754: eflags |= CC_C | CC_A; ! 1755: } else { ! 1756: eflags &= ~(CC_C | CC_A); ! 1757: al &= 0x0f; ! 1758: } ! 1759: EAX = (EAX & ~0xffff) | al | (ah << 8); ! 1760: CC_SRC = eflags; ! 1761: } ! 1762: ! 1763: void helper_aas(void) ! 1764: { ! 1765: int icarry; ! 1766: int al, ah, af; ! 1767: int eflags; ! 1768: ! 1769: eflags = helper_cc_compute_all(CC_OP); ! 1770: af = eflags & CC_A; ! 1771: al = EAX & 0xff; ! 1772: ah = (EAX >> 8) & 0xff; ! 1773: ! 1774: icarry = (al < 6); ! 1775: if (((al & 0x0f) > 9 ) || af) { ! 1776: al = (al - 6) & 0x0f; ! 1777: ah = (ah - 1 - icarry) & 0xff; ! 1778: eflags |= CC_C | CC_A; ! 1779: } else { ! 1780: eflags &= ~(CC_C | CC_A); ! 1781: al &= 0x0f; ! 1782: } ! 1783: EAX = (EAX & ~0xffff) | al | (ah << 8); ! 1784: CC_SRC = eflags; ! 1785: } ! 1786: ! 1787: void helper_daa(void) ! 1788: { ! 1789: int al, af, cf; ! 1790: int eflags; ! 1791: ! 1792: eflags = helper_cc_compute_all(CC_OP); ! 1793: cf = eflags & CC_C; ! 1794: af = eflags & CC_A; ! 1795: al = EAX & 0xff; ! 1796: ! 1797: eflags = 0; ! 1798: if (((al & 0x0f) > 9 ) || af) { ! 1799: al = (al + 6) & 0xff; ! 1800: eflags |= CC_A; ! 1801: } ! 1802: if ((al > 0x9f) || cf) { ! 1803: al = (al + 0x60) & 0xff; ! 1804: eflags |= CC_C; ! 1805: } ! 1806: EAX = (EAX & ~0xff) | al; ! 1807: /* well, speed is not an issue here, so we compute the flags by hand */ ! 1808: eflags |= (al == 0) << 6; /* zf */ ! 1809: eflags |= parity_table[al]; /* pf */ ! 1810: eflags |= (al & 0x80); /* sf */ ! 1811: CC_SRC = eflags; ! 1812: } ! 1813: ! 1814: void helper_das(void) ! 1815: { ! 1816: int al, al1, af, cf; ! 1817: int eflags; ! 1818: ! 1819: eflags = helper_cc_compute_all(CC_OP); ! 1820: cf = eflags & CC_C; ! 1821: af = eflags & CC_A; ! 1822: al = EAX & 0xff; ! 1823: ! 1824: eflags = 0; ! 1825: al1 = al; ! 1826: if (((al & 0x0f) > 9 ) || af) { ! 1827: eflags |= CC_A; ! 1828: if (al < 6 || cf) ! 1829: eflags |= CC_C; ! 1830: al = (al - 6) & 0xff; ! 1831: } ! 1832: if ((al1 > 0x99) || cf) { ! 1833: al = (al - 0x60) & 0xff; ! 1834: eflags |= CC_C; ! 1835: } ! 1836: EAX = (EAX & ~0xff) | al; ! 1837: /* well, speed is not an issue here, so we compute the flags by hand */ ! 1838: eflags |= (al == 0) << 6; /* zf */ ! 1839: eflags |= parity_table[al]; /* pf */ ! 1840: eflags |= (al & 0x80); /* sf */ ! 1841: CC_SRC = eflags; ! 1842: } ! 1843: ! 1844: void helper_into(int next_eip_addend) ! 1845: { ! 1846: int eflags; ! 1847: eflags = helper_cc_compute_all(CC_OP); ! 1848: if (eflags & CC_O) { ! 1849: raise_interrupt(EXCP04_INTO, 1, 0, next_eip_addend); ! 1850: } ! 1851: } ! 1852: ! 1853: void helper_cmpxchg8b(target_ulong a0) ! 1854: { ! 1855: uint64_t d; ! 1856: int eflags; ! 1857: ! 1858: eflags = helper_cc_compute_all(CC_OP); ! 1859: d = ldq(a0); ! 1860: if (d == (((uint64_t)EDX << 32) | (uint32_t)EAX)) { ! 1861: stq(a0, ((uint64_t)ECX << 32) | (uint32_t)EBX); ! 1862: eflags |= CC_Z; ! 1863: } else { ! 1864: /* always do the store */ ! 1865: stq(a0, d); ! 1866: EDX = (uint32_t)(d >> 32); ! 1867: EAX = (uint32_t)d; ! 1868: eflags &= ~CC_Z; ! 1869: } ! 1870: CC_SRC = eflags; ! 1871: } ! 1872: ! 1873: #ifdef TARGET_X86_64 ! 1874: void helper_cmpxchg16b(target_ulong a0) ! 1875: { ! 1876: uint64_t d0, d1; ! 1877: int eflags; ! 1878: ! 1879: if ((a0 & 0xf) != 0) ! 1880: raise_exception(EXCP0D_GPF); ! 1881: eflags = helper_cc_compute_all(CC_OP); ! 1882: d0 = ldq(a0); ! 1883: d1 = ldq(a0 + 8); ! 1884: if (d0 == EAX && d1 == EDX) { ! 1885: stq(a0, EBX); ! 1886: stq(a0 + 8, ECX); ! 1887: eflags |= CC_Z; ! 1888: } else { ! 1889: /* always do the store */ ! 1890: stq(a0, d0); ! 1891: stq(a0 + 8, d1); ! 1892: EDX = d1; ! 1893: EAX = d0; ! 1894: eflags &= ~CC_Z; ! 1895: } ! 1896: CC_SRC = eflags; ! 1897: } ! 1898: #endif ! 1899: ! 1900: void helper_single_step(void) ! 1901: { ! 1902: #ifndef CONFIG_USER_ONLY ! 1903: check_hw_breakpoints(env, 1); ! 1904: env->dr[6] |= DR6_BS; ! 1905: #endif ! 1906: raise_exception(EXCP01_DB); ! 1907: } ! 1908: ! 1909: void helper_cpuid(void) ! 1910: { ! 1911: uint32_t eax, ebx, ecx, edx; ! 1912: ! 1913: helper_svm_check_intercept_param(SVM_EXIT_CPUID, 0); ! 1914: ! 1915: cpu_x86_cpuid(env, (uint32_t)EAX, (uint32_t)ECX, &eax, &ebx, &ecx, &edx); ! 1916: EAX = eax; ! 1917: EBX = ebx; ! 1918: ECX = ecx; ! 1919: EDX = edx; ! 1920: } ! 1921: ! 1922: void helper_enter_level(int level, int data32, target_ulong t1) ! 1923: { ! 1924: target_ulong ssp; ! 1925: uint32_t esp_mask, esp, ebp; ! 1926: ! 1927: esp_mask = get_sp_mask(env->segs[R_SS].flags); ! 1928: ssp = env->segs[R_SS].base; ! 1929: ebp = EBP; ! 1930: esp = ESP; ! 1931: if (data32) { ! 1932: /* 32 bit */ ! 1933: esp -= 4; ! 1934: while (--level) { ! 1935: esp -= 4; ! 1936: ebp -= 4; ! 1937: stl(ssp + (esp & esp_mask), ldl(ssp + (ebp & esp_mask))); ! 1938: } ! 1939: esp -= 4; ! 1940: stl(ssp + (esp & esp_mask), t1); ! 1941: } else { ! 1942: /* 16 bit */ ! 1943: esp -= 2; ! 1944: while (--level) { ! 1945: esp -= 2; ! 1946: ebp -= 2; ! 1947: stw(ssp + (esp & esp_mask), lduw(ssp + (ebp & esp_mask))); ! 1948: } ! 1949: esp -= 2; ! 1950: stw(ssp + (esp & esp_mask), t1); ! 1951: } ! 1952: } ! 1953: ! 1954: #ifdef TARGET_X86_64 ! 1955: void helper_enter64_level(int level, int data64, target_ulong t1) ! 1956: { ! 1957: target_ulong esp, ebp; ! 1958: ebp = EBP; ! 1959: esp = ESP; ! 1960: ! 1961: if (data64) { ! 1962: /* 64 bit */ ! 1963: esp -= 8; ! 1964: while (--level) { ! 1965: esp -= 8; ! 1966: ebp -= 8; ! 1967: stq(esp, ldq(ebp)); ! 1968: } ! 1969: esp -= 8; ! 1970: stq(esp, t1); ! 1971: } else { ! 1972: /* 16 bit */ ! 1973: esp -= 2; ! 1974: while (--level) { ! 1975: esp -= 2; ! 1976: ebp -= 2; ! 1977: stw(esp, lduw(ebp)); ! 1978: } ! 1979: esp -= 2; ! 1980: stw(esp, t1); ! 1981: } ! 1982: } ! 1983: #endif ! 1984: ! 1985: void helper_lldt(int selector) ! 1986: { ! 1987: SegmentCache *dt; ! 1988: uint32_t e1, e2; ! 1989: int index, entry_limit; ! 1990: target_ulong ptr; ! 1991: ! 1992: selector &= 0xffff; ! 1993: if ((selector & 0xfffc) == 0) { ! 1994: /* XXX: NULL selector case: invalid LDT */ ! 1995: env->ldt.base = 0; ! 1996: env->ldt.limit = 0; ! 1997: } else { ! 1998: if (selector & 0x4) ! 1999: raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ! 2000: dt = &env->gdt; ! 2001: index = selector & ~7; ! 2002: #ifdef TARGET_X86_64 ! 2003: if (env->hflags & HF_LMA_MASK) ! 2004: entry_limit = 15; ! 2005: else ! 2006: #endif ! 2007: entry_limit = 7; ! 2008: if ((index + entry_limit) > dt->limit) ! 2009: raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ! 2010: ptr = dt->base + index; ! 2011: e1 = ldl_kernel(ptr); ! 2012: e2 = ldl_kernel(ptr + 4); ! 2013: if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2) ! 2014: raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ! 2015: if (!(e2 & DESC_P_MASK)) ! 2016: raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); ! 2017: #ifdef TARGET_X86_64 ! 2018: if (env->hflags & HF_LMA_MASK) { ! 2019: uint32_t e3; ! 2020: e3 = ldl_kernel(ptr + 8); ! 2021: load_seg_cache_raw_dt(&env->ldt, e1, e2); ! 2022: env->ldt.base |= (target_ulong)e3 << 32; ! 2023: } else ! 2024: #endif ! 2025: { ! 2026: load_seg_cache_raw_dt(&env->ldt, e1, e2); ! 2027: } ! 2028: } ! 2029: env->ldt.selector = selector; ! 2030: } ! 2031: ! 2032: void helper_ltr(int selector) ! 2033: { ! 2034: SegmentCache *dt; ! 2035: uint32_t e1, e2; ! 2036: int index, type, entry_limit; ! 2037: target_ulong ptr; ! 2038: ! 2039: selector &= 0xffff; ! 2040: if ((selector & 0xfffc) == 0) { ! 2041: /* NULL selector case: invalid TR */ ! 2042: env->tr.base = 0; ! 2043: env->tr.limit = 0; ! 2044: env->tr.flags = 0; ! 2045: } else { ! 2046: if (selector & 0x4) ! 2047: raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ! 2048: dt = &env->gdt; ! 2049: index = selector & ~7; ! 2050: #ifdef TARGET_X86_64 ! 2051: if (env->hflags & HF_LMA_MASK) ! 2052: entry_limit = 15; ! 2053: else ! 2054: #endif ! 2055: entry_limit = 7; ! 2056: if ((index + entry_limit) > dt->limit) ! 2057: raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ! 2058: ptr = dt->base + index; ! 2059: e1 = ldl_kernel(ptr); ! 2060: e2 = ldl_kernel(ptr + 4); ! 2061: type = (e2 >> DESC_TYPE_SHIFT) & 0xf; ! 2062: if ((e2 & DESC_S_MASK) || ! 2063: (type != 1 && type != 9)) ! 2064: raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ! 2065: if (!(e2 & DESC_P_MASK)) ! 2066: raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); ! 2067: #ifdef TARGET_X86_64 ! 2068: if (env->hflags & HF_LMA_MASK) { ! 2069: uint32_t e3, e4; ! 2070: e3 = ldl_kernel(ptr + 8); ! 2071: e4 = ldl_kernel(ptr + 12); ! 2072: if ((e4 >> DESC_TYPE_SHIFT) & 0xf) ! 2073: raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ! 2074: load_seg_cache_raw_dt(&env->tr, e1, e2); ! 2075: env->tr.base |= (target_ulong)e3 << 32; ! 2076: } else ! 2077: #endif ! 2078: { ! 2079: load_seg_cache_raw_dt(&env->tr, e1, e2); ! 2080: } ! 2081: e2 |= DESC_TSS_BUSY_MASK; ! 2082: stl_kernel(ptr + 4, e2); ! 2083: } ! 2084: env->tr.selector = selector; ! 2085: } ! 2086: ! 2087: /* only works if protected mode and not VM86. seg_reg must be != R_CS */ ! 2088: void helper_load_seg(int seg_reg, int selector) ! 2089: { ! 2090: uint32_t e1, e2; ! 2091: int cpl, dpl, rpl; ! 2092: SegmentCache *dt; ! 2093: int index; ! 2094: target_ulong ptr; ! 2095: ! 2096: selector &= 0xffff; ! 2097: cpl = env->hflags & HF_CPL_MASK; ! 2098: if ((selector & 0xfffc) == 0) { ! 2099: /* null selector case */ ! 2100: if (seg_reg == R_SS ! 2101: #ifdef TARGET_X86_64 ! 2102: && (!(env->hflags & HF_CS64_MASK) || cpl == 3) ! 2103: #endif ! 2104: ) ! 2105: raise_exception_err(EXCP0D_GPF, 0); ! 2106: cpu_x86_load_seg_cache(env, seg_reg, selector, 0, 0, 0); ! 2107: } else { ! 2108: ! 2109: if (selector & 0x4) ! 2110: dt = &env->ldt; ! 2111: else ! 2112: dt = &env->gdt; ! 2113: index = selector & ~7; ! 2114: if ((index + 7) > dt->limit) ! 2115: raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ! 2116: ptr = dt->base + index; ! 2117: e1 = ldl_kernel(ptr); ! 2118: e2 = ldl_kernel(ptr + 4); ! 2119: ! 2120: if (!(e2 & DESC_S_MASK)) ! 2121: raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ! 2122: rpl = selector & 3; ! 2123: dpl = (e2 >> DESC_DPL_SHIFT) & 3; ! 2124: if (seg_reg == R_SS) { ! 2125: /* must be writable segment */ ! 2126: if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK)) ! 2127: raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ! 2128: if (rpl != cpl || dpl != cpl) ! 2129: raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ! 2130: } else { ! 2131: /* must be readable segment */ ! 2132: if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) ! 2133: raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ! 2134: ! 2135: if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) { ! 2136: /* if not conforming code, test rights */ ! 2137: if (dpl < cpl || dpl < rpl) ! 2138: raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ! 2139: } ! 2140: } ! 2141: ! 2142: if (!(e2 & DESC_P_MASK)) { ! 2143: if (seg_reg == R_SS) ! 2144: raise_exception_err(EXCP0C_STACK, selector & 0xfffc); ! 2145: else ! 2146: raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); ! 2147: } ! 2148: ! 2149: /* set the access bit if not already set */ ! 2150: if (!(e2 & DESC_A_MASK)) { ! 2151: e2 |= DESC_A_MASK; ! 2152: stl_kernel(ptr + 4, e2); ! 2153: } ! 2154: ! 2155: cpu_x86_load_seg_cache(env, seg_reg, selector, ! 2156: get_seg_base(e1, e2), ! 2157: get_seg_limit(e1, e2), ! 2158: e2); ! 2159: #if 0 ! 2160: qemu_log("load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx flags=%08x\n", ! 2161: selector, (unsigned long)sc->base, sc->limit, sc->flags); ! 2162: #endif ! 2163: } ! 2164: } ! 2165: ! 2166: /* protected mode jump */ ! 2167: void helper_ljmp_protected(int new_cs, target_ulong new_eip, ! 2168: int next_eip_addend) ! 2169: { ! 2170: int gate_cs, type; ! 2171: uint32_t e1, e2, cpl, dpl, rpl, limit; ! 2172: target_ulong next_eip; ! 2173: ! 2174: if ((new_cs & 0xfffc) == 0) ! 2175: raise_exception_err(EXCP0D_GPF, 0); ! 2176: if (load_segment(&e1, &e2, new_cs) != 0) ! 2177: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); ! 2178: cpl = env->hflags & HF_CPL_MASK; ! 2179: if (e2 & DESC_S_MASK) { ! 2180: if (!(e2 & DESC_CS_MASK)) ! 2181: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); ! 2182: dpl = (e2 >> DESC_DPL_SHIFT) & 3; ! 2183: if (e2 & DESC_C_MASK) { ! 2184: /* conforming code segment */ ! 2185: if (dpl > cpl) ! 2186: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); ! 2187: } else { ! 2188: /* non conforming code segment */ ! 2189: rpl = new_cs & 3; ! 2190: if (rpl > cpl) ! 2191: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); ! 2192: if (dpl != cpl) ! 2193: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); ! 2194: } ! 2195: if (!(e2 & DESC_P_MASK)) ! 2196: raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); ! 2197: limit = get_seg_limit(e1, e2); ! 2198: if (new_eip > limit && ! 2199: !(env->hflags & HF_LMA_MASK) && !(e2 & DESC_L_MASK)) ! 2200: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); ! 2201: cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl, ! 2202: get_seg_base(e1, e2), limit, e2); ! 2203: EIP = new_eip; ! 2204: } else { ! 2205: /* jump to call or task gate */ ! 2206: dpl = (e2 >> DESC_DPL_SHIFT) & 3; ! 2207: rpl = new_cs & 3; ! 2208: cpl = env->hflags & HF_CPL_MASK; ! 2209: type = (e2 >> DESC_TYPE_SHIFT) & 0xf; ! 2210: switch(type) { ! 2211: case 1: /* 286 TSS */ ! 2212: case 9: /* 386 TSS */ ! 2213: case 5: /* task gate */ ! 2214: if (dpl < cpl || dpl < rpl) ! 2215: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); ! 2216: next_eip = env->eip + next_eip_addend; ! 2217: switch_tss(new_cs, e1, e2, SWITCH_TSS_JMP, next_eip); ! 2218: CC_OP = CC_OP_EFLAGS; ! 2219: break; ! 2220: case 4: /* 286 call gate */ ! 2221: case 12: /* 386 call gate */ ! 2222: if ((dpl < cpl) || (dpl < rpl)) ! 2223: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); ! 2224: if (!(e2 & DESC_P_MASK)) ! 2225: raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); ! 2226: gate_cs = e1 >> 16; ! 2227: new_eip = (e1 & 0xffff); ! 2228: if (type == 12) ! 2229: new_eip |= (e2 & 0xffff0000); ! 2230: if (load_segment(&e1, &e2, gate_cs) != 0) ! 2231: raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc); ! 2232: dpl = (e2 >> DESC_DPL_SHIFT) & 3; ! 2233: /* must be code segment */ ! 2234: if (((e2 & (DESC_S_MASK | DESC_CS_MASK)) != ! 2235: (DESC_S_MASK | DESC_CS_MASK))) ! 2236: raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc); ! 2237: if (((e2 & DESC_C_MASK) && (dpl > cpl)) || ! 2238: (!(e2 & DESC_C_MASK) && (dpl != cpl))) ! 2239: raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc); ! 2240: if (!(e2 & DESC_P_MASK)) ! 2241: raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc); ! 2242: limit = get_seg_limit(e1, e2); ! 2243: if (new_eip > limit) ! 2244: raise_exception_err(EXCP0D_GPF, 0); ! 2245: cpu_x86_load_seg_cache(env, R_CS, (gate_cs & 0xfffc) | cpl, ! 2246: get_seg_base(e1, e2), limit, e2); ! 2247: EIP = new_eip; ! 2248: break; ! 2249: default: ! 2250: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); ! 2251: break; ! 2252: } ! 2253: } ! 2254: } ! 2255: ! 2256: /* real mode call */ ! 2257: void helper_lcall_real(int new_cs, target_ulong new_eip1, ! 2258: int shift, int next_eip) ! 2259: { ! 2260: int new_eip; ! 2261: uint32_t esp, esp_mask; ! 2262: target_ulong ssp; ! 2263: ! 2264: new_eip = new_eip1; ! 2265: esp = ESP; ! 2266: esp_mask = get_sp_mask(env->segs[R_SS].flags); ! 2267: ssp = env->segs[R_SS].base; ! 2268: if (shift) { ! 2269: PUSHL(ssp, esp, esp_mask, env->segs[R_CS].selector); ! 2270: PUSHL(ssp, esp, esp_mask, next_eip); ! 2271: } else { ! 2272: PUSHW(ssp, esp, esp_mask, env->segs[R_CS].selector); ! 2273: PUSHW(ssp, esp, esp_mask, next_eip); ! 2274: } ! 2275: ! 2276: SET_ESP(esp, esp_mask); ! 2277: env->eip = new_eip; ! 2278: env->segs[R_CS].selector = new_cs; ! 2279: env->segs[R_CS].base = (new_cs << 4); ! 2280: } ! 2281: ! 2282: /* protected mode call */ ! 2283: void helper_lcall_protected(int new_cs, target_ulong new_eip, ! 2284: int shift, int next_eip_addend) ! 2285: { ! 2286: int new_stack, i; ! 2287: uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count; ! 2288: uint32_t ss = 0, ss_e1 = 0, ss_e2 = 0, sp, type, ss_dpl, sp_mask; ! 2289: uint32_t val, limit, old_sp_mask; ! 2290: target_ulong ssp, old_ssp, next_eip; ! 2291: ! 2292: next_eip = env->eip + next_eip_addend; ! 2293: LOG_PCALL("lcall %04x:%08x s=%d\n", new_cs, (uint32_t)new_eip, shift); ! 2294: LOG_PCALL_STATE(env); ! 2295: if ((new_cs & 0xfffc) == 0) ! 2296: raise_exception_err(EXCP0D_GPF, 0); ! 2297: if (load_segment(&e1, &e2, new_cs) != 0) ! 2298: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); ! 2299: cpl = env->hflags & HF_CPL_MASK; ! 2300: LOG_PCALL("desc=%08x:%08x\n", e1, e2); ! 2301: if (e2 & DESC_S_MASK) { ! 2302: if (!(e2 & DESC_CS_MASK)) ! 2303: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); ! 2304: dpl = (e2 >> DESC_DPL_SHIFT) & 3; ! 2305: if (e2 & DESC_C_MASK) { ! 2306: /* conforming code segment */ ! 2307: if (dpl > cpl) ! 2308: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); ! 2309: } else { ! 2310: /* non conforming code segment */ ! 2311: rpl = new_cs & 3; ! 2312: if (rpl > cpl) ! 2313: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); ! 2314: if (dpl != cpl) ! 2315: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); ! 2316: } ! 2317: if (!(e2 & DESC_P_MASK)) ! 2318: raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); ! 2319: ! 2320: #ifdef TARGET_X86_64 ! 2321: /* XXX: check 16/32 bit cases in long mode */ ! 2322: if (shift == 2) { ! 2323: target_ulong rsp; ! 2324: /* 64 bit case */ ! 2325: rsp = ESP; ! 2326: PUSHQ(rsp, env->segs[R_CS].selector); ! 2327: PUSHQ(rsp, next_eip); ! 2328: /* from this point, not restartable */ ! 2329: ESP = rsp; ! 2330: cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl, ! 2331: get_seg_base(e1, e2), ! 2332: get_seg_limit(e1, e2), e2); ! 2333: EIP = new_eip; ! 2334: } else ! 2335: #endif ! 2336: { ! 2337: sp = ESP; ! 2338: sp_mask = get_sp_mask(env->segs[R_SS].flags); ! 2339: ssp = env->segs[R_SS].base; ! 2340: if (shift) { ! 2341: PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector); ! 2342: PUSHL(ssp, sp, sp_mask, next_eip); ! 2343: } else { ! 2344: PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector); ! 2345: PUSHW(ssp, sp, sp_mask, next_eip); ! 2346: } ! 2347: ! 2348: limit = get_seg_limit(e1, e2); ! 2349: if (new_eip > limit) ! 2350: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); ! 2351: /* from this point, not restartable */ ! 2352: SET_ESP(sp, sp_mask); ! 2353: cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl, ! 2354: get_seg_base(e1, e2), limit, e2); ! 2355: EIP = new_eip; ! 2356: } ! 2357: } else { ! 2358: /* check gate type */ ! 2359: type = (e2 >> DESC_TYPE_SHIFT) & 0x1f; ! 2360: dpl = (e2 >> DESC_DPL_SHIFT) & 3; ! 2361: rpl = new_cs & 3; ! 2362: switch(type) { ! 2363: case 1: /* available 286 TSS */ ! 2364: case 9: /* available 386 TSS */ ! 2365: case 5: /* task gate */ ! 2366: if (dpl < cpl || dpl < rpl) ! 2367: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); ! 2368: switch_tss(new_cs, e1, e2, SWITCH_TSS_CALL, next_eip); ! 2369: CC_OP = CC_OP_EFLAGS; ! 2370: return; ! 2371: case 4: /* 286 call gate */ ! 2372: case 12: /* 386 call gate */ ! 2373: break; ! 2374: default: ! 2375: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); ! 2376: break; ! 2377: } ! 2378: shift = type >> 3; ! 2379: ! 2380: if (dpl < cpl || dpl < rpl) ! 2381: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); ! 2382: /* check valid bit */ ! 2383: if (!(e2 & DESC_P_MASK)) ! 2384: raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); ! 2385: selector = e1 >> 16; ! 2386: offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff); ! 2387: param_count = e2 & 0x1f; ! 2388: if ((selector & 0xfffc) == 0) ! 2389: raise_exception_err(EXCP0D_GPF, 0); ! 2390: ! 2391: if (load_segment(&e1, &e2, selector) != 0) ! 2392: raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ! 2393: if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK))) ! 2394: raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ! 2395: dpl = (e2 >> DESC_DPL_SHIFT) & 3; ! 2396: if (dpl > cpl) ! 2397: raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ! 2398: if (!(e2 & DESC_P_MASK)) ! 2399: raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); ! 2400: ! 2401: if (!(e2 & DESC_C_MASK) && dpl < cpl) { ! 2402: /* to inner privilege */ ! 2403: get_ss_esp_from_tss(&ss, &sp, dpl); ! 2404: LOG_PCALL("new ss:esp=%04x:%08x param_count=%d ESP=" TARGET_FMT_lx "\n", ! 2405: ss, sp, param_count, ESP); ! 2406: if ((ss & 0xfffc) == 0) ! 2407: raise_exception_err(EXCP0A_TSS, ss & 0xfffc); ! 2408: if ((ss & 3) != dpl) ! 2409: raise_exception_err(EXCP0A_TSS, ss & 0xfffc); ! 2410: if (load_segment(&ss_e1, &ss_e2, ss) != 0) ! 2411: raise_exception_err(EXCP0A_TSS, ss & 0xfffc); ! 2412: ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3; ! 2413: if (ss_dpl != dpl) ! 2414: raise_exception_err(EXCP0A_TSS, ss & 0xfffc); ! 2415: if (!(ss_e2 & DESC_S_MASK) || ! 2416: (ss_e2 & DESC_CS_MASK) || ! 2417: !(ss_e2 & DESC_W_MASK)) ! 2418: raise_exception_err(EXCP0A_TSS, ss & 0xfffc); ! 2419: if (!(ss_e2 & DESC_P_MASK)) ! 2420: raise_exception_err(EXCP0A_TSS, ss & 0xfffc); ! 2421: ! 2422: // push_size = ((param_count * 2) + 8) << shift; ! 2423: ! 2424: old_sp_mask = get_sp_mask(env->segs[R_SS].flags); ! 2425: old_ssp = env->segs[R_SS].base; ! 2426: ! 2427: sp_mask = get_sp_mask(ss_e2); ! 2428: ssp = get_seg_base(ss_e1, ss_e2); ! 2429: if (shift) { ! 2430: PUSHL(ssp, sp, sp_mask, env->segs[R_SS].selector); ! 2431: PUSHL(ssp, sp, sp_mask, ESP); ! 2432: for(i = param_count - 1; i >= 0; i--) { ! 2433: val = ldl_kernel(old_ssp + ((ESP + i * 4) & old_sp_mask)); ! 2434: PUSHL(ssp, sp, sp_mask, val); ! 2435: } ! 2436: } else { ! 2437: PUSHW(ssp, sp, sp_mask, env->segs[R_SS].selector); ! 2438: PUSHW(ssp, sp, sp_mask, ESP); ! 2439: for(i = param_count - 1; i >= 0; i--) { ! 2440: val = lduw_kernel(old_ssp + ((ESP + i * 2) & old_sp_mask)); ! 2441: PUSHW(ssp, sp, sp_mask, val); ! 2442: } ! 2443: } ! 2444: new_stack = 1; ! 2445: } else { ! 2446: /* to same privilege */ ! 2447: sp = ESP; ! 2448: sp_mask = get_sp_mask(env->segs[R_SS].flags); ! 2449: ssp = env->segs[R_SS].base; ! 2450: // push_size = (4 << shift); ! 2451: new_stack = 0; ! 2452: } ! 2453: ! 2454: if (shift) { ! 2455: PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector); ! 2456: PUSHL(ssp, sp, sp_mask, next_eip); ! 2457: } else { ! 2458: PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector); ! 2459: PUSHW(ssp, sp, sp_mask, next_eip); ! 2460: } ! 2461: ! 2462: /* from this point, not restartable */ ! 2463: ! 2464: if (new_stack) { ! 2465: ss = (ss & ~3) | dpl; ! 2466: cpu_x86_load_seg_cache(env, R_SS, ss, ! 2467: ssp, ! 2468: get_seg_limit(ss_e1, ss_e2), ! 2469: ss_e2); ! 2470: } ! 2471: ! 2472: selector = (selector & ~3) | dpl; ! 2473: cpu_x86_load_seg_cache(env, R_CS, selector, ! 2474: get_seg_base(e1, e2), ! 2475: get_seg_limit(e1, e2), ! 2476: e2); ! 2477: cpu_x86_set_cpl(env, dpl); ! 2478: SET_ESP(sp, sp_mask); ! 2479: EIP = offset; ! 2480: } ! 2481: #ifdef USE_KQEMU ! 2482: if (kqemu_is_ok(env)) { ! 2483: env->exception_index = -1; ! 2484: cpu_loop_exit(); ! 2485: } ! 2486: #endif ! 2487: } ! 2488: ! 2489: /* real and vm86 mode iret */ ! 2490: void helper_iret_real(int shift) ! 2491: { ! 2492: uint32_t sp, new_cs, new_eip, new_eflags, sp_mask; ! 2493: target_ulong ssp; ! 2494: int eflags_mask; ! 2495: ! 2496: sp_mask = 0xffff; /* XXXX: use SS segment size ? */ ! 2497: sp = ESP; ! 2498: ssp = env->segs[R_SS].base; ! 2499: if (shift == 1) { ! 2500: /* 32 bits */ ! 2501: POPL(ssp, sp, sp_mask, new_eip); ! 2502: POPL(ssp, sp, sp_mask, new_cs); ! 2503: new_cs &= 0xffff; ! 2504: POPL(ssp, sp, sp_mask, new_eflags); ! 2505: } else { ! 2506: /* 16 bits */ ! 2507: POPW(ssp, sp, sp_mask, new_eip); ! 2508: POPW(ssp, sp, sp_mask, new_cs); ! 2509: POPW(ssp, sp, sp_mask, new_eflags); ! 2510: } ! 2511: ESP = (ESP & ~sp_mask) | (sp & sp_mask); ! 2512: env->segs[R_CS].selector = new_cs; ! 2513: env->segs[R_CS].base = (new_cs << 4); ! 2514: env->eip = new_eip; ! 2515: if (env->eflags & VM_MASK) ! 2516: eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | RF_MASK | NT_MASK; ! 2517: else ! 2518: eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | IOPL_MASK | RF_MASK | NT_MASK; ! 2519: if (shift == 0) ! 2520: eflags_mask &= 0xffff; ! 2521: load_eflags(new_eflags, eflags_mask); ! 2522: env->hflags2 &= ~HF2_NMI_MASK; ! 2523: } ! 2524: ! 2525: static inline void validate_seg(int seg_reg, int cpl) ! 2526: { ! 2527: int dpl; ! 2528: uint32_t e2; ! 2529: ! 2530: /* XXX: on x86_64, we do not want to nullify FS and GS because ! 2531: they may still contain a valid base. I would be interested to ! 2532: know how a real x86_64 CPU behaves */ ! 2533: if ((seg_reg == R_FS || seg_reg == R_GS) && ! 2534: (env->segs[seg_reg].selector & 0xfffc) == 0) ! 2535: return; ! 2536: ! 2537: e2 = env->segs[seg_reg].flags; ! 2538: dpl = (e2 >> DESC_DPL_SHIFT) & 3; ! 2539: if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) { ! 2540: /* data or non conforming code segment */ ! 2541: if (dpl < cpl) { ! 2542: cpu_x86_load_seg_cache(env, seg_reg, 0, 0, 0, 0); ! 2543: } ! 2544: } ! 2545: } ! 2546: ! 2547: /* protected mode iret */ ! 2548: static inline void helper_ret_protected(int shift, int is_iret, int addend) ! 2549: { ! 2550: uint32_t new_cs, new_eflags, new_ss; ! 2551: uint32_t new_es, new_ds, new_fs, new_gs; ! 2552: uint32_t e1, e2, ss_e1, ss_e2; ! 2553: int cpl, dpl, rpl, eflags_mask, iopl; ! 2554: target_ulong ssp, sp, new_eip, new_esp, sp_mask; ! 2555: ! 2556: #ifdef TARGET_X86_64 ! 2557: if (shift == 2) ! 2558: sp_mask = -1; ! 2559: else ! 2560: #endif ! 2561: sp_mask = get_sp_mask(env->segs[R_SS].flags); ! 2562: sp = ESP; ! 2563: ssp = env->segs[R_SS].base; ! 2564: new_eflags = 0; /* avoid warning */ ! 2565: #ifdef TARGET_X86_64 ! 2566: if (shift == 2) { ! 2567: POPQ(sp, new_eip); ! 2568: POPQ(sp, new_cs); ! 2569: new_cs &= 0xffff; ! 2570: if (is_iret) { ! 2571: POPQ(sp, new_eflags); ! 2572: } ! 2573: } else ! 2574: #endif ! 2575: if (shift == 1) { ! 2576: /* 32 bits */ ! 2577: POPL(ssp, sp, sp_mask, new_eip); ! 2578: POPL(ssp, sp, sp_mask, new_cs); ! 2579: new_cs &= 0xffff; ! 2580: if (is_iret) { ! 2581: POPL(ssp, sp, sp_mask, new_eflags); ! 2582: if (new_eflags & VM_MASK) ! 2583: goto return_to_vm86; ! 2584: } ! 2585: } else { ! 2586: /* 16 bits */ ! 2587: POPW(ssp, sp, sp_mask, new_eip); ! 2588: POPW(ssp, sp, sp_mask, new_cs); ! 2589: if (is_iret) ! 2590: POPW(ssp, sp, sp_mask, new_eflags); ! 2591: } ! 2592: LOG_PCALL("lret new %04x:" TARGET_FMT_lx " s=%d addend=0x%x\n", ! 2593: new_cs, new_eip, shift, addend); ! 2594: LOG_PCALL_STATE(env); ! 2595: if ((new_cs & 0xfffc) == 0) ! 2596: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); ! 2597: if (load_segment(&e1, &e2, new_cs) != 0) ! 2598: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); ! 2599: if (!(e2 & DESC_S_MASK) || ! 2600: !(e2 & DESC_CS_MASK)) ! 2601: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); ! 2602: cpl = env->hflags & HF_CPL_MASK; ! 2603: rpl = new_cs & 3; ! 2604: if (rpl < cpl) ! 2605: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); ! 2606: dpl = (e2 >> DESC_DPL_SHIFT) & 3; ! 2607: if (e2 & DESC_C_MASK) { ! 2608: if (dpl > rpl) ! 2609: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); ! 2610: } else { ! 2611: if (dpl != rpl) ! 2612: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); ! 2613: } ! 2614: if (!(e2 & DESC_P_MASK)) ! 2615: raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); ! 2616: ! 2617: sp += addend; ! 2618: if (rpl == cpl && (!(env->hflags & HF_CS64_MASK) || ! 2619: ((env->hflags & HF_CS64_MASK) && !is_iret))) { ! 2620: /* return to same privilege level */ ! 2621: cpu_x86_load_seg_cache(env, R_CS, new_cs, ! 2622: get_seg_base(e1, e2), ! 2623: get_seg_limit(e1, e2), ! 2624: e2); ! 2625: } else { ! 2626: /* return to different privilege level */ ! 2627: #ifdef TARGET_X86_64 ! 2628: if (shift == 2) { ! 2629: POPQ(sp, new_esp); ! 2630: POPQ(sp, new_ss); ! 2631: new_ss &= 0xffff; ! 2632: } else ! 2633: #endif ! 2634: if (shift == 1) { ! 2635: /* 32 bits */ ! 2636: POPL(ssp, sp, sp_mask, new_esp); ! 2637: POPL(ssp, sp, sp_mask, new_ss); ! 2638: new_ss &= 0xffff; ! 2639: } else { ! 2640: /* 16 bits */ ! 2641: POPW(ssp, sp, sp_mask, new_esp); ! 2642: POPW(ssp, sp, sp_mask, new_ss); ! 2643: } ! 2644: LOG_PCALL("new ss:esp=%04x:" TARGET_FMT_lx "\n", ! 2645: new_ss, new_esp); ! 2646: if ((new_ss & 0xfffc) == 0) { ! 2647: #ifdef TARGET_X86_64 ! 2648: /* NULL ss is allowed in long mode if cpl != 3*/ ! 2649: /* XXX: test CS64 ? */ ! 2650: if ((env->hflags & HF_LMA_MASK) && rpl != 3) { ! 2651: cpu_x86_load_seg_cache(env, R_SS, new_ss, ! 2652: 0, 0xffffffff, ! 2653: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | ! 2654: DESC_S_MASK | (rpl << DESC_DPL_SHIFT) | ! 2655: DESC_W_MASK | DESC_A_MASK); ! 2656: ss_e2 = DESC_B_MASK; /* XXX: should not be needed ? */ ! 2657: } else ! 2658: #endif ! 2659: { ! 2660: raise_exception_err(EXCP0D_GPF, 0); ! 2661: } ! 2662: } else { ! 2663: if ((new_ss & 3) != rpl) ! 2664: raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); ! 2665: if (load_segment(&ss_e1, &ss_e2, new_ss) != 0) ! 2666: raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); ! 2667: if (!(ss_e2 & DESC_S_MASK) || ! 2668: (ss_e2 & DESC_CS_MASK) || ! 2669: !(ss_e2 & DESC_W_MASK)) ! 2670: raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); ! 2671: dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3; ! 2672: if (dpl != rpl) ! 2673: raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); ! 2674: if (!(ss_e2 & DESC_P_MASK)) ! 2675: raise_exception_err(EXCP0B_NOSEG, new_ss & 0xfffc); ! 2676: cpu_x86_load_seg_cache(env, R_SS, new_ss, ! 2677: get_seg_base(ss_e1, ss_e2), ! 2678: get_seg_limit(ss_e1, ss_e2), ! 2679: ss_e2); ! 2680: } ! 2681: ! 2682: cpu_x86_load_seg_cache(env, R_CS, new_cs, ! 2683: get_seg_base(e1, e2), ! 2684: get_seg_limit(e1, e2), ! 2685: e2); ! 2686: cpu_x86_set_cpl(env, rpl); ! 2687: sp = new_esp; ! 2688: #ifdef TARGET_X86_64 ! 2689: if (env->hflags & HF_CS64_MASK) ! 2690: sp_mask = -1; ! 2691: else ! 2692: #endif ! 2693: sp_mask = get_sp_mask(ss_e2); ! 2694: ! 2695: /* validate data segments */ ! 2696: validate_seg(R_ES, rpl); ! 2697: validate_seg(R_DS, rpl); ! 2698: validate_seg(R_FS, rpl); ! 2699: validate_seg(R_GS, rpl); ! 2700: ! 2701: sp += addend; ! 2702: } ! 2703: SET_ESP(sp, sp_mask); ! 2704: env->eip = new_eip; ! 2705: if (is_iret) { ! 2706: /* NOTE: 'cpl' is the _old_ CPL */ ! 2707: eflags_mask = TF_MASK | AC_MASK | ID_MASK | RF_MASK | NT_MASK; ! 2708: if (cpl == 0) ! 2709: eflags_mask |= IOPL_MASK; ! 2710: iopl = (env->eflags >> IOPL_SHIFT) & 3; ! 2711: if (cpl <= iopl) ! 2712: eflags_mask |= IF_MASK; ! 2713: if (shift == 0) ! 2714: eflags_mask &= 0xffff; ! 2715: load_eflags(new_eflags, eflags_mask); ! 2716: } ! 2717: return; ! 2718: ! 2719: return_to_vm86: ! 2720: POPL(ssp, sp, sp_mask, new_esp); ! 2721: POPL(ssp, sp, sp_mask, new_ss); ! 2722: POPL(ssp, sp, sp_mask, new_es); ! 2723: POPL(ssp, sp, sp_mask, new_ds); ! 2724: POPL(ssp, sp, sp_mask, new_fs); ! 2725: POPL(ssp, sp, sp_mask, new_gs); ! 2726: ! 2727: /* modify processor state */ ! 2728: load_eflags(new_eflags, TF_MASK | AC_MASK | ID_MASK | ! 2729: IF_MASK | IOPL_MASK | VM_MASK | NT_MASK | VIF_MASK | VIP_MASK); ! 2730: load_seg_vm(R_CS, new_cs & 0xffff); ! 2731: cpu_x86_set_cpl(env, 3); ! 2732: load_seg_vm(R_SS, new_ss & 0xffff); ! 2733: load_seg_vm(R_ES, new_es & 0xffff); ! 2734: load_seg_vm(R_DS, new_ds & 0xffff); ! 2735: load_seg_vm(R_FS, new_fs & 0xffff); ! 2736: load_seg_vm(R_GS, new_gs & 0xffff); ! 2737: ! 2738: env->eip = new_eip & 0xffff; ! 2739: ESP = new_esp; ! 2740: } ! 2741: ! 2742: void helper_iret_protected(int shift, int next_eip) ! 2743: { ! 2744: int tss_selector, type; ! 2745: uint32_t e1, e2; ! 2746: ! 2747: /* specific case for TSS */ ! 2748: if (env->eflags & NT_MASK) { ! 2749: #ifdef TARGET_X86_64 ! 2750: if (env->hflags & HF_LMA_MASK) ! 2751: raise_exception_err(EXCP0D_GPF, 0); ! 2752: #endif ! 2753: tss_selector = lduw_kernel(env->tr.base + 0); ! 2754: if (tss_selector & 4) ! 2755: raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc); ! 2756: if (load_segment(&e1, &e2, tss_selector) != 0) ! 2757: raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc); ! 2758: type = (e2 >> DESC_TYPE_SHIFT) & 0x17; ! 2759: /* NOTE: we check both segment and busy TSS */ ! 2760: if (type != 3) ! 2761: raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc); ! 2762: switch_tss(tss_selector, e1, e2, SWITCH_TSS_IRET, next_eip); ! 2763: } else { ! 2764: helper_ret_protected(shift, 1, 0); ! 2765: } ! 2766: env->hflags2 &= ~HF2_NMI_MASK; ! 2767: #ifdef USE_KQEMU ! 2768: if (kqemu_is_ok(env)) { ! 2769: CC_OP = CC_OP_EFLAGS; ! 2770: env->exception_index = -1; ! 2771: cpu_loop_exit(); ! 2772: } ! 2773: #endif ! 2774: } ! 2775: ! 2776: void helper_lret_protected(int shift, int addend) ! 2777: { ! 2778: helper_ret_protected(shift, 0, addend); ! 2779: #ifdef USE_KQEMU ! 2780: if (kqemu_is_ok(env)) { ! 2781: env->exception_index = -1; ! 2782: cpu_loop_exit(); ! 2783: } ! 2784: #endif ! 2785: } ! 2786: ! 2787: void helper_sysenter(void) ! 2788: { ! 2789: if (env->sysenter_cs == 0) { ! 2790: raise_exception_err(EXCP0D_GPF, 0); ! 2791: } ! 2792: env->eflags &= ~(VM_MASK | IF_MASK | RF_MASK); ! 2793: cpu_x86_set_cpl(env, 0); ! 2794: ! 2795: #ifdef TARGET_X86_64 ! 2796: if (env->hflags & HF_LMA_MASK) { ! 2797: cpu_x86_load_seg_cache(env, R_CS, env->sysenter_cs & 0xfffc, ! 2798: 0, 0xffffffff, ! 2799: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | ! 2800: DESC_S_MASK | ! 2801: DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK); ! 2802: } else ! 2803: #endif ! 2804: { ! 2805: cpu_x86_load_seg_cache(env, R_CS, env->sysenter_cs & 0xfffc, ! 2806: 0, 0xffffffff, ! 2807: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | ! 2808: DESC_S_MASK | ! 2809: DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); ! 2810: } ! 2811: cpu_x86_load_seg_cache(env, R_SS, (env->sysenter_cs + 8) & 0xfffc, ! 2812: 0, 0xffffffff, ! 2813: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | ! 2814: DESC_S_MASK | ! 2815: DESC_W_MASK | DESC_A_MASK); ! 2816: ESP = env->sysenter_esp; ! 2817: EIP = env->sysenter_eip; ! 2818: } ! 2819: ! 2820: void helper_sysexit(int dflag) ! 2821: { ! 2822: int cpl; ! 2823: ! 2824: cpl = env->hflags & HF_CPL_MASK; ! 2825: if (env->sysenter_cs == 0 || cpl != 0) { ! 2826: raise_exception_err(EXCP0D_GPF, 0); ! 2827: } ! 2828: cpu_x86_set_cpl(env, 3); ! 2829: #ifdef TARGET_X86_64 ! 2830: if (dflag == 2) { ! 2831: cpu_x86_load_seg_cache(env, R_CS, ((env->sysenter_cs + 32) & 0xfffc) | 3, ! 2832: 0, 0xffffffff, ! 2833: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | ! 2834: DESC_S_MASK | (3 << DESC_DPL_SHIFT) | ! 2835: DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK); ! 2836: cpu_x86_load_seg_cache(env, R_SS, ((env->sysenter_cs + 40) & 0xfffc) | 3, ! 2837: 0, 0xffffffff, ! 2838: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | ! 2839: DESC_S_MASK | (3 << DESC_DPL_SHIFT) | ! 2840: DESC_W_MASK | DESC_A_MASK); ! 2841: } else ! 2842: #endif ! 2843: { ! 2844: cpu_x86_load_seg_cache(env, R_CS, ((env->sysenter_cs + 16) & 0xfffc) | 3, ! 2845: 0, 0xffffffff, ! 2846: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | ! 2847: DESC_S_MASK | (3 << DESC_DPL_SHIFT) | ! 2848: DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); ! 2849: cpu_x86_load_seg_cache(env, R_SS, ((env->sysenter_cs + 24) & 0xfffc) | 3, ! 2850: 0, 0xffffffff, ! 2851: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | ! 2852: DESC_S_MASK | (3 << DESC_DPL_SHIFT) | ! 2853: DESC_W_MASK | DESC_A_MASK); ! 2854: } ! 2855: ESP = ECX; ! 2856: EIP = EDX; ! 2857: #ifdef USE_KQEMU ! 2858: if (kqemu_is_ok(env)) { ! 2859: env->exception_index = -1; ! 2860: cpu_loop_exit(); ! 2861: } ! 2862: #endif ! 2863: } ! 2864: ! 2865: #if defined(CONFIG_USER_ONLY) ! 2866: target_ulong helper_read_crN(int reg) ! 2867: { ! 2868: return 0; ! 2869: } ! 2870: ! 2871: void helper_write_crN(int reg, target_ulong t0) ! 2872: { ! 2873: } ! 2874: ! 2875: void helper_movl_drN_T0(int reg, target_ulong t0) ! 2876: { ! 2877: } ! 2878: #else ! 2879: target_ulong helper_read_crN(int reg) ! 2880: { ! 2881: target_ulong val; ! 2882: ! 2883: helper_svm_check_intercept_param(SVM_EXIT_READ_CR0 + reg, 0); ! 2884: switch(reg) { ! 2885: default: ! 2886: val = env->cr[reg]; ! 2887: break; ! 2888: case 8: ! 2889: if (!(env->hflags2 & HF2_VINTR_MASK)) { ! 2890: val = cpu_get_apic_tpr(env); ! 2891: } else { ! 2892: val = env->v_tpr; ! 2893: } ! 2894: break; ! 2895: } ! 2896: return val; ! 2897: } ! 2898: ! 2899: void helper_write_crN(int reg, target_ulong t0) ! 2900: { ! 2901: helper_svm_check_intercept_param(SVM_EXIT_WRITE_CR0 + reg, 0); ! 2902: switch(reg) { ! 2903: case 0: ! 2904: cpu_x86_update_cr0(env, t0); ! 2905: break; ! 2906: case 3: ! 2907: cpu_x86_update_cr3(env, t0); ! 2908: break; ! 2909: case 4: ! 2910: cpu_x86_update_cr4(env, t0); ! 2911: break; ! 2912: case 8: ! 2913: if (!(env->hflags2 & HF2_VINTR_MASK)) { ! 2914: cpu_set_apic_tpr(env, t0); ! 2915: } ! 2916: env->v_tpr = t0 & 0x0f; ! 2917: break; ! 2918: default: ! 2919: env->cr[reg] = t0; ! 2920: break; ! 2921: } ! 2922: } ! 2923: ! 2924: void helper_movl_drN_T0(int reg, target_ulong t0) ! 2925: { ! 2926: int i; ! 2927: ! 2928: if (reg < 4) { ! 2929: hw_breakpoint_remove(env, reg); ! 2930: env->dr[reg] = t0; ! 2931: hw_breakpoint_insert(env, reg); ! 2932: } else if (reg == 7) { ! 2933: for (i = 0; i < 4; i++) ! 2934: hw_breakpoint_remove(env, i); ! 2935: env->dr[7] = t0; ! 2936: for (i = 0; i < 4; i++) ! 2937: hw_breakpoint_insert(env, i); ! 2938: } else ! 2939: env->dr[reg] = t0; ! 2940: } ! 2941: #endif ! 2942: ! 2943: void helper_lmsw(target_ulong t0) ! 2944: { ! 2945: /* only 4 lower bits of CR0 are modified. PE cannot be set to zero ! 2946: if already set to one. */ ! 2947: t0 = (env->cr[0] & ~0xe) | (t0 & 0xf); ! 2948: helper_write_crN(0, t0); ! 2949: } ! 2950: ! 2951: void helper_clts(void) ! 2952: { ! 2953: env->cr[0] &= ~CR0_TS_MASK; ! 2954: env->hflags &= ~HF_TS_MASK; ! 2955: } ! 2956: ! 2957: void helper_invlpg(target_ulong addr) ! 2958: { ! 2959: helper_svm_check_intercept_param(SVM_EXIT_INVLPG, 0); ! 2960: tlb_flush_page(env, addr); ! 2961: } ! 2962: ! 2963: void helper_rdtsc(void) ! 2964: { ! 2965: uint64_t val; ! 2966: ! 2967: if ((env->cr[4] & CR4_TSD_MASK) && ((env->hflags & HF_CPL_MASK) != 0)) { ! 2968: raise_exception(EXCP0D_GPF); ! 2969: } ! 2970: helper_svm_check_intercept_param(SVM_EXIT_RDTSC, 0); ! 2971: ! 2972: val = cpu_get_tsc(env) + env->tsc_offset; ! 2973: EAX = (uint32_t)(val); ! 2974: EDX = (uint32_t)(val >> 32); ! 2975: } ! 2976: ! 2977: void helper_rdpmc(void) ! 2978: { ! 2979: if ((env->cr[4] & CR4_PCE_MASK) && ((env->hflags & HF_CPL_MASK) != 0)) { ! 2980: raise_exception(EXCP0D_GPF); ! 2981: } ! 2982: helper_svm_check_intercept_param(SVM_EXIT_RDPMC, 0); ! 2983: ! 2984: /* currently unimplemented */ ! 2985: raise_exception_err(EXCP06_ILLOP, 0); ! 2986: } ! 2987: ! 2988: #if defined(CONFIG_USER_ONLY) ! 2989: void helper_wrmsr(void) ! 2990: { ! 2991: } ! 2992: ! 2993: void helper_rdmsr(void) ! 2994: { ! 2995: } ! 2996: #else ! 2997: void helper_wrmsr(void) ! 2998: { ! 2999: uint64_t val; ! 3000: ! 3001: helper_svm_check_intercept_param(SVM_EXIT_MSR, 1); ! 3002: ! 3003: val = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32); ! 3004: ! 3005: switch((uint32_t)ECX) { ! 3006: case MSR_IA32_SYSENTER_CS: ! 3007: env->sysenter_cs = val & 0xffff; ! 3008: break; ! 3009: case MSR_IA32_SYSENTER_ESP: ! 3010: env->sysenter_esp = val; ! 3011: break; ! 3012: case MSR_IA32_SYSENTER_EIP: ! 3013: env->sysenter_eip = val; ! 3014: break; ! 3015: case MSR_IA32_APICBASE: ! 3016: cpu_set_apic_base(env, val); ! 3017: break; ! 3018: case MSR_EFER: ! 3019: { ! 3020: uint64_t update_mask; ! 3021: update_mask = 0; ! 3022: if (env->cpuid_ext2_features & CPUID_EXT2_SYSCALL) ! 3023: update_mask |= MSR_EFER_SCE; ! 3024: if (env->cpuid_ext2_features & CPUID_EXT2_LM) ! 3025: update_mask |= MSR_EFER_LME; ! 3026: if (env->cpuid_ext2_features & CPUID_EXT2_FFXSR) ! 3027: update_mask |= MSR_EFER_FFXSR; ! 3028: if (env->cpuid_ext2_features & CPUID_EXT2_NX) ! 3029: update_mask |= MSR_EFER_NXE; ! 3030: if (env->cpuid_ext3_features & CPUID_EXT3_SVM) ! 3031: update_mask |= MSR_EFER_SVME; ! 3032: if (env->cpuid_ext2_features & CPUID_EXT2_FFXSR) ! 3033: update_mask |= MSR_EFER_FFXSR; ! 3034: cpu_load_efer(env, (env->efer & ~update_mask) | ! 3035: (val & update_mask)); ! 3036: } ! 3037: break; ! 3038: case MSR_STAR: ! 3039: env->star = val; ! 3040: break; ! 3041: case MSR_PAT: ! 3042: env->pat = val; ! 3043: break; ! 3044: case MSR_VM_HSAVE_PA: ! 3045: env->vm_hsave = val; ! 3046: break; ! 3047: #ifdef TARGET_X86_64 ! 3048: case MSR_LSTAR: ! 3049: env->lstar = val; ! 3050: break; ! 3051: case MSR_CSTAR: ! 3052: env->cstar = val; ! 3053: break; ! 3054: case MSR_FMASK: ! 3055: env->fmask = val; ! 3056: break; ! 3057: case MSR_FSBASE: ! 3058: env->segs[R_FS].base = val; ! 3059: break; ! 3060: case MSR_GSBASE: ! 3061: env->segs[R_GS].base = val; ! 3062: break; ! 3063: case MSR_KERNELGSBASE: ! 3064: env->kernelgsbase = val; ! 3065: break; ! 3066: #endif ! 3067: case MSR_MTRRphysBase(0): ! 3068: case MSR_MTRRphysBase(1): ! 3069: case MSR_MTRRphysBase(2): ! 3070: case MSR_MTRRphysBase(3): ! 3071: case MSR_MTRRphysBase(4): ! 3072: case MSR_MTRRphysBase(5): ! 3073: case MSR_MTRRphysBase(6): ! 3074: case MSR_MTRRphysBase(7): ! 3075: env->mtrr_var[((uint32_t)ECX - MSR_MTRRphysBase(0)) / 2].base = val; ! 3076: break; ! 3077: case MSR_MTRRphysMask(0): ! 3078: case MSR_MTRRphysMask(1): ! 3079: case MSR_MTRRphysMask(2): ! 3080: case MSR_MTRRphysMask(3): ! 3081: case MSR_MTRRphysMask(4): ! 3082: case MSR_MTRRphysMask(5): ! 3083: case MSR_MTRRphysMask(6): ! 3084: case MSR_MTRRphysMask(7): ! 3085: env->mtrr_var[((uint32_t)ECX - MSR_MTRRphysMask(0)) / 2].mask = val; ! 3086: break; ! 3087: case MSR_MTRRfix64K_00000: ! 3088: env->mtrr_fixed[(uint32_t)ECX - MSR_MTRRfix64K_00000] = val; ! 3089: break; ! 3090: case MSR_MTRRfix16K_80000: ! 3091: case MSR_MTRRfix16K_A0000: ! 3092: env->mtrr_fixed[(uint32_t)ECX - MSR_MTRRfix16K_80000 + 1] = val; ! 3093: break; ! 3094: case MSR_MTRRfix4K_C0000: ! 3095: case MSR_MTRRfix4K_C8000: ! 3096: case MSR_MTRRfix4K_D0000: ! 3097: case MSR_MTRRfix4K_D8000: ! 3098: case MSR_MTRRfix4K_E0000: ! 3099: case MSR_MTRRfix4K_E8000: ! 3100: case MSR_MTRRfix4K_F0000: ! 3101: case MSR_MTRRfix4K_F8000: ! 3102: env->mtrr_fixed[(uint32_t)ECX - MSR_MTRRfix4K_C0000 + 3] = val; ! 3103: break; ! 3104: case MSR_MTRRdefType: ! 3105: env->mtrr_deftype = val; ! 3106: break; ! 3107: default: ! 3108: /* XXX: exception ? */ ! 3109: break; ! 3110: } ! 3111: } ! 3112: ! 3113: void helper_rdmsr(void) ! 3114: { ! 3115: uint64_t val; ! 3116: ! 3117: helper_svm_check_intercept_param(SVM_EXIT_MSR, 0); ! 3118: ! 3119: switch((uint32_t)ECX) { ! 3120: case MSR_IA32_SYSENTER_CS: ! 3121: val = env->sysenter_cs; ! 3122: break; ! 3123: case MSR_IA32_SYSENTER_ESP: ! 3124: val = env->sysenter_esp; ! 3125: break; ! 3126: case MSR_IA32_SYSENTER_EIP: ! 3127: val = env->sysenter_eip; ! 3128: break; ! 3129: case MSR_IA32_APICBASE: ! 3130: val = cpu_get_apic_base(env); ! 3131: break; ! 3132: case MSR_EFER: ! 3133: val = env->efer; ! 3134: break; ! 3135: case MSR_STAR: ! 3136: val = env->star; ! 3137: break; ! 3138: case MSR_PAT: ! 3139: val = env->pat; ! 3140: break; ! 3141: case MSR_VM_HSAVE_PA: ! 3142: val = env->vm_hsave; ! 3143: break; ! 3144: case MSR_IA32_PERF_STATUS: ! 3145: /* tsc_increment_by_tick */ ! 3146: val = 1000ULL; ! 3147: /* CPU multiplier */ ! 3148: val |= (((uint64_t)4ULL) << 40); ! 3149: break; ! 3150: #ifdef TARGET_X86_64 ! 3151: case MSR_LSTAR: ! 3152: val = env->lstar; ! 3153: break; ! 3154: case MSR_CSTAR: ! 3155: val = env->cstar; ! 3156: break; ! 3157: case MSR_FMASK: ! 3158: val = env->fmask; ! 3159: break; ! 3160: case MSR_FSBASE: ! 3161: val = env->segs[R_FS].base; ! 3162: break; ! 3163: case MSR_GSBASE: ! 3164: val = env->segs[R_GS].base; ! 3165: break; ! 3166: case MSR_KERNELGSBASE: ! 3167: val = env->kernelgsbase; ! 3168: break; ! 3169: #endif ! 3170: #ifdef USE_KQEMU ! 3171: case MSR_QPI_COMMBASE: ! 3172: if (env->kqemu_enabled) { ! 3173: val = kqemu_comm_base; ! 3174: } else { ! 3175: val = 0; ! 3176: } ! 3177: break; ! 3178: #endif ! 3179: case MSR_MTRRphysBase(0): ! 3180: case MSR_MTRRphysBase(1): ! 3181: case MSR_MTRRphysBase(2): ! 3182: case MSR_MTRRphysBase(3): ! 3183: case MSR_MTRRphysBase(4): ! 3184: case MSR_MTRRphysBase(5): ! 3185: case MSR_MTRRphysBase(6): ! 3186: case MSR_MTRRphysBase(7): ! 3187: val = env->mtrr_var[((uint32_t)ECX - MSR_MTRRphysBase(0)) / 2].base; ! 3188: break; ! 3189: case MSR_MTRRphysMask(0): ! 3190: case MSR_MTRRphysMask(1): ! 3191: case MSR_MTRRphysMask(2): ! 3192: case MSR_MTRRphysMask(3): ! 3193: case MSR_MTRRphysMask(4): ! 3194: case MSR_MTRRphysMask(5): ! 3195: case MSR_MTRRphysMask(6): ! 3196: case MSR_MTRRphysMask(7): ! 3197: val = env->mtrr_var[((uint32_t)ECX - MSR_MTRRphysMask(0)) / 2].mask; ! 3198: break; ! 3199: case MSR_MTRRfix64K_00000: ! 3200: val = env->mtrr_fixed[0]; ! 3201: break; ! 3202: case MSR_MTRRfix16K_80000: ! 3203: case MSR_MTRRfix16K_A0000: ! 3204: val = env->mtrr_fixed[(uint32_t)ECX - MSR_MTRRfix16K_80000 + 1]; ! 3205: break; ! 3206: case MSR_MTRRfix4K_C0000: ! 3207: case MSR_MTRRfix4K_C8000: ! 3208: case MSR_MTRRfix4K_D0000: ! 3209: case MSR_MTRRfix4K_D8000: ! 3210: case MSR_MTRRfix4K_E0000: ! 3211: case MSR_MTRRfix4K_E8000: ! 3212: case MSR_MTRRfix4K_F0000: ! 3213: case MSR_MTRRfix4K_F8000: ! 3214: val = env->mtrr_fixed[(uint32_t)ECX - MSR_MTRRfix4K_C0000 + 3]; ! 3215: break; ! 3216: case MSR_MTRRdefType: ! 3217: val = env->mtrr_deftype; ! 3218: break; ! 3219: case MSR_MTRRcap: ! 3220: if (env->cpuid_features & CPUID_MTRR) ! 3221: val = MSR_MTRRcap_VCNT | MSR_MTRRcap_FIXRANGE_SUPPORT | MSR_MTRRcap_WC_SUPPORTED; ! 3222: else ! 3223: /* XXX: exception ? */ ! 3224: val = 0; ! 3225: break; ! 3226: default: ! 3227: /* XXX: exception ? */ ! 3228: val = 0; ! 3229: break; ! 3230: } ! 3231: EAX = (uint32_t)(val); ! 3232: EDX = (uint32_t)(val >> 32); ! 3233: } ! 3234: #endif ! 3235: ! 3236: target_ulong helper_lsl(target_ulong selector1) ! 3237: { ! 3238: unsigned int limit; ! 3239: uint32_t e1, e2, eflags, selector; ! 3240: int rpl, dpl, cpl, type; ! 3241: ! 3242: selector = selector1 & 0xffff; ! 3243: eflags = helper_cc_compute_all(CC_OP); ! 3244: if (load_segment(&e1, &e2, selector) != 0) ! 3245: goto fail; ! 3246: rpl = selector & 3; ! 3247: dpl = (e2 >> DESC_DPL_SHIFT) & 3; ! 3248: cpl = env->hflags & HF_CPL_MASK; ! 3249: if (e2 & DESC_S_MASK) { ! 3250: if ((e2 & DESC_CS_MASK) && (e2 & DESC_C_MASK)) { ! 3251: /* conforming */ ! 3252: } else { ! 3253: if (dpl < cpl || dpl < rpl) ! 3254: goto fail; ! 3255: } ! 3256: } else { ! 3257: type = (e2 >> DESC_TYPE_SHIFT) & 0xf; ! 3258: switch(type) { ! 3259: case 1: ! 3260: case 2: ! 3261: case 3: ! 3262: case 9: ! 3263: case 11: ! 3264: break; ! 3265: default: ! 3266: goto fail; ! 3267: } ! 3268: if (dpl < cpl || dpl < rpl) { ! 3269: fail: ! 3270: CC_SRC = eflags & ~CC_Z; ! 3271: return 0; ! 3272: } ! 3273: } ! 3274: limit = get_seg_limit(e1, e2); ! 3275: CC_SRC = eflags | CC_Z; ! 3276: return limit; ! 3277: } ! 3278: ! 3279: target_ulong helper_lar(target_ulong selector1) ! 3280: { ! 3281: uint32_t e1, e2, eflags, selector; ! 3282: int rpl, dpl, cpl, type; ! 3283: ! 3284: selector = selector1 & 0xffff; ! 3285: eflags = helper_cc_compute_all(CC_OP); ! 3286: if ((selector & 0xfffc) == 0) ! 3287: goto fail; ! 3288: if (load_segment(&e1, &e2, selector) != 0) ! 3289: goto fail; ! 3290: rpl = selector & 3; ! 3291: dpl = (e2 >> DESC_DPL_SHIFT) & 3; ! 3292: cpl = env->hflags & HF_CPL_MASK; ! 3293: if (e2 & DESC_S_MASK) { ! 3294: if ((e2 & DESC_CS_MASK) && (e2 & DESC_C_MASK)) { ! 3295: /* conforming */ ! 3296: } else { ! 3297: if (dpl < cpl || dpl < rpl) ! 3298: goto fail; ! 3299: } ! 3300: } else { ! 3301: type = (e2 >> DESC_TYPE_SHIFT) & 0xf; ! 3302: switch(type) { ! 3303: case 1: ! 3304: case 2: ! 3305: case 3: ! 3306: case 4: ! 3307: case 5: ! 3308: case 9: ! 3309: case 11: ! 3310: case 12: ! 3311: break; ! 3312: default: ! 3313: goto fail; ! 3314: } ! 3315: if (dpl < cpl || dpl < rpl) { ! 3316: fail: ! 3317: CC_SRC = eflags & ~CC_Z; ! 3318: return 0; ! 3319: } ! 3320: } ! 3321: CC_SRC = eflags | CC_Z; ! 3322: return e2 & 0x00f0ff00; ! 3323: } ! 3324: ! 3325: void helper_verr(target_ulong selector1) ! 3326: { ! 3327: uint32_t e1, e2, eflags, selector; ! 3328: int rpl, dpl, cpl; ! 3329: ! 3330: selector = selector1 & 0xffff; ! 3331: eflags = helper_cc_compute_all(CC_OP); ! 3332: if ((selector & 0xfffc) == 0) ! 3333: goto fail; ! 3334: if (load_segment(&e1, &e2, selector) != 0) ! 3335: goto fail; ! 3336: if (!(e2 & DESC_S_MASK)) ! 3337: goto fail; ! 3338: rpl = selector & 3; ! 3339: dpl = (e2 >> DESC_DPL_SHIFT) & 3; ! 3340: cpl = env->hflags & HF_CPL_MASK; ! 3341: if (e2 & DESC_CS_MASK) { ! 3342: if (!(e2 & DESC_R_MASK)) ! 3343: goto fail; ! 3344: if (!(e2 & DESC_C_MASK)) { ! 3345: if (dpl < cpl || dpl < rpl) ! 3346: goto fail; ! 3347: } ! 3348: } else { ! 3349: if (dpl < cpl || dpl < rpl) { ! 3350: fail: ! 3351: CC_SRC = eflags & ~CC_Z; ! 3352: return; ! 3353: } ! 3354: } ! 3355: CC_SRC = eflags | CC_Z; ! 3356: } ! 3357: ! 3358: void helper_verw(target_ulong selector1) ! 3359: { ! 3360: uint32_t e1, e2, eflags, selector; ! 3361: int rpl, dpl, cpl; ! 3362: ! 3363: selector = selector1 & 0xffff; ! 3364: eflags = helper_cc_compute_all(CC_OP); ! 3365: if ((selector & 0xfffc) == 0) ! 3366: goto fail; ! 3367: if (load_segment(&e1, &e2, selector) != 0) ! 3368: goto fail; ! 3369: if (!(e2 & DESC_S_MASK)) ! 3370: goto fail; ! 3371: rpl = selector & 3; ! 3372: dpl = (e2 >> DESC_DPL_SHIFT) & 3; ! 3373: cpl = env->hflags & HF_CPL_MASK; ! 3374: if (e2 & DESC_CS_MASK) { ! 3375: goto fail; ! 3376: } else { ! 3377: if (dpl < cpl || dpl < rpl) ! 3378: goto fail; ! 3379: if (!(e2 & DESC_W_MASK)) { ! 3380: fail: ! 3381: CC_SRC = eflags & ~CC_Z; ! 3382: return; ! 3383: } ! 3384: } ! 3385: CC_SRC = eflags | CC_Z; ! 3386: } ! 3387: ! 3388: /* x87 FPU helpers */ ! 3389: ! 3390: static void fpu_set_exception(int mask) ! 3391: { ! 3392: env->fpus |= mask; ! 3393: if (env->fpus & (~env->fpuc & FPUC_EM)) ! 3394: env->fpus |= FPUS_SE | FPUS_B; ! 3395: } ! 3396: ! 3397: static inline CPU86_LDouble helper_fdiv(CPU86_LDouble a, CPU86_LDouble b) ! 3398: { ! 3399: if (b == 0.0) ! 3400: fpu_set_exception(FPUS_ZE); ! 3401: return a / b; ! 3402: } ! 3403: ! 3404: static void fpu_raise_exception(void) ! 3405: { ! 3406: if (env->cr[0] & CR0_NE_MASK) { ! 3407: raise_exception(EXCP10_COPR); ! 3408: } ! 3409: #if !defined(CONFIG_USER_ONLY) ! 3410: else { ! 3411: cpu_set_ferr(env); ! 3412: } ! 3413: #endif ! 3414: } ! 3415: ! 3416: void helper_flds_FT0(uint32_t val) ! 3417: { ! 3418: union { ! 3419: float32 f; ! 3420: uint32_t i; ! 3421: } u; ! 3422: u.i = val; ! 3423: FT0 = float32_to_floatx(u.f, &env->fp_status); ! 3424: } ! 3425: ! 3426: void helper_fldl_FT0(uint64_t val) ! 3427: { ! 3428: union { ! 3429: float64 f; ! 3430: uint64_t i; ! 3431: } u; ! 3432: u.i = val; ! 3433: FT0 = float64_to_floatx(u.f, &env->fp_status); ! 3434: } ! 3435: ! 3436: void helper_fildl_FT0(int32_t val) ! 3437: { ! 3438: FT0 = int32_to_floatx(val, &env->fp_status); ! 3439: } ! 3440: ! 3441: void helper_flds_ST0(uint32_t val) ! 3442: { ! 3443: int new_fpstt; ! 3444: union { ! 3445: float32 f; ! 3446: uint32_t i; ! 3447: } u; ! 3448: new_fpstt = (env->fpstt - 1) & 7; ! 3449: u.i = val; ! 3450: env->fpregs[new_fpstt].d = float32_to_floatx(u.f, &env->fp_status); ! 3451: env->fpstt = new_fpstt; ! 3452: env->fptags[new_fpstt] = 0; /* validate stack entry */ ! 3453: } ! 3454: ! 3455: void helper_fldl_ST0(uint64_t val) ! 3456: { ! 3457: int new_fpstt; ! 3458: union { ! 3459: float64 f; ! 3460: uint64_t i; ! 3461: } u; ! 3462: new_fpstt = (env->fpstt - 1) & 7; ! 3463: u.i = val; ! 3464: env->fpregs[new_fpstt].d = float64_to_floatx(u.f, &env->fp_status); ! 3465: env->fpstt = new_fpstt; ! 3466: env->fptags[new_fpstt] = 0; /* validate stack entry */ ! 3467: } ! 3468: ! 3469: void helper_fildl_ST0(int32_t val) ! 3470: { ! 3471: int new_fpstt; ! 3472: new_fpstt = (env->fpstt - 1) & 7; ! 3473: env->fpregs[new_fpstt].d = int32_to_floatx(val, &env->fp_status); ! 3474: env->fpstt = new_fpstt; ! 3475: env->fptags[new_fpstt] = 0; /* validate stack entry */ ! 3476: } ! 3477: ! 3478: void helper_fildll_ST0(int64_t val) ! 3479: { ! 3480: int new_fpstt; ! 3481: new_fpstt = (env->fpstt - 1) & 7; ! 3482: env->fpregs[new_fpstt].d = int64_to_floatx(val, &env->fp_status); ! 3483: env->fpstt = new_fpstt; ! 3484: env->fptags[new_fpstt] = 0; /* validate stack entry */ ! 3485: } ! 3486: ! 3487: uint32_t helper_fsts_ST0(void) ! 3488: { ! 3489: union { ! 3490: float32 f; ! 3491: uint32_t i; ! 3492: } u; ! 3493: u.f = floatx_to_float32(ST0, &env->fp_status); ! 3494: return u.i; ! 3495: } ! 3496: ! 3497: uint64_t helper_fstl_ST0(void) ! 3498: { ! 3499: union { ! 3500: float64 f; ! 3501: uint64_t i; ! 3502: } u; ! 3503: u.f = floatx_to_float64(ST0, &env->fp_status); ! 3504: return u.i; ! 3505: } ! 3506: ! 3507: int32_t helper_fist_ST0(void) ! 3508: { ! 3509: int32_t val; ! 3510: val = floatx_to_int32(ST0, &env->fp_status); ! 3511: if (val != (int16_t)val) ! 3512: val = -32768; ! 3513: return val; ! 3514: } ! 3515: ! 3516: int32_t helper_fistl_ST0(void) ! 3517: { ! 3518: int32_t val; ! 3519: val = floatx_to_int32(ST0, &env->fp_status); ! 3520: return val; ! 3521: } ! 3522: ! 3523: int64_t helper_fistll_ST0(void) ! 3524: { ! 3525: int64_t val; ! 3526: val = floatx_to_int64(ST0, &env->fp_status); ! 3527: return val; ! 3528: } ! 3529: ! 3530: int32_t helper_fistt_ST0(void) ! 3531: { ! 3532: int32_t val; ! 3533: val = floatx_to_int32_round_to_zero(ST0, &env->fp_status); ! 3534: if (val != (int16_t)val) ! 3535: val = -32768; ! 3536: return val; ! 3537: } ! 3538: ! 3539: int32_t helper_fisttl_ST0(void) ! 3540: { ! 3541: int32_t val; ! 3542: val = floatx_to_int32_round_to_zero(ST0, &env->fp_status); ! 3543: return val; ! 3544: } ! 3545: ! 3546: int64_t helper_fisttll_ST0(void) ! 3547: { ! 3548: int64_t val; ! 3549: val = floatx_to_int64_round_to_zero(ST0, &env->fp_status); ! 3550: return val; ! 3551: } ! 3552: ! 3553: void helper_fldt_ST0(target_ulong ptr) ! 3554: { ! 3555: int new_fpstt; ! 3556: new_fpstt = (env->fpstt - 1) & 7; ! 3557: env->fpregs[new_fpstt].d = helper_fldt(ptr); ! 3558: env->fpstt = new_fpstt; ! 3559: env->fptags[new_fpstt] = 0; /* validate stack entry */ ! 3560: } ! 3561: ! 3562: void helper_fstt_ST0(target_ulong ptr) ! 3563: { ! 3564: helper_fstt(ST0, ptr); ! 3565: } ! 3566: ! 3567: void helper_fpush(void) ! 3568: { ! 3569: fpush(); ! 3570: } ! 3571: ! 3572: void helper_fpop(void) ! 3573: { ! 3574: fpop(); ! 3575: } ! 3576: ! 3577: void helper_fdecstp(void) ! 3578: { ! 3579: env->fpstt = (env->fpstt - 1) & 7; ! 3580: env->fpus &= (~0x4700); ! 3581: } ! 3582: ! 3583: void helper_fincstp(void) ! 3584: { ! 3585: env->fpstt = (env->fpstt + 1) & 7; ! 3586: env->fpus &= (~0x4700); ! 3587: } ! 3588: ! 3589: /* FPU move */ ! 3590: ! 3591: void helper_ffree_STN(int st_index) ! 3592: { ! 3593: env->fptags[(env->fpstt + st_index) & 7] = 1; ! 3594: } ! 3595: ! 3596: void helper_fmov_ST0_FT0(void) ! 3597: { ! 3598: ST0 = FT0; ! 3599: } ! 3600: ! 3601: void helper_fmov_FT0_STN(int st_index) ! 3602: { ! 3603: FT0 = ST(st_index); ! 3604: } ! 3605: ! 3606: void helper_fmov_ST0_STN(int st_index) ! 3607: { ! 3608: ST0 = ST(st_index); ! 3609: } ! 3610: ! 3611: void helper_fmov_STN_ST0(int st_index) ! 3612: { ! 3613: ST(st_index) = ST0; ! 3614: } ! 3615: ! 3616: void helper_fxchg_ST0_STN(int st_index) ! 3617: { ! 3618: CPU86_LDouble tmp; ! 3619: tmp = ST(st_index); ! 3620: ST(st_index) = ST0; ! 3621: ST0 = tmp; ! 3622: } ! 3623: ! 3624: /* FPU operations */ ! 3625: ! 3626: static const int fcom_ccval[4] = {0x0100, 0x4000, 0x0000, 0x4500}; ! 3627: ! 3628: void helper_fcom_ST0_FT0(void) ! 3629: { ! 3630: int ret; ! 3631: ! 3632: ret = floatx_compare(ST0, FT0, &env->fp_status); ! 3633: env->fpus = (env->fpus & ~0x4500) | fcom_ccval[ret + 1]; ! 3634: } ! 3635: ! 3636: void helper_fucom_ST0_FT0(void) ! 3637: { ! 3638: int ret; ! 3639: ! 3640: ret = floatx_compare_quiet(ST0, FT0, &env->fp_status); ! 3641: env->fpus = (env->fpus & ~0x4500) | fcom_ccval[ret+ 1]; ! 3642: } ! 3643: ! 3644: static const int fcomi_ccval[4] = {CC_C, CC_Z, 0, CC_Z | CC_P | CC_C}; ! 3645: ! 3646: void helper_fcomi_ST0_FT0(void) ! 3647: { ! 3648: int eflags; ! 3649: int ret; ! 3650: ! 3651: ret = floatx_compare(ST0, FT0, &env->fp_status); ! 3652: eflags = helper_cc_compute_all(CC_OP); ! 3653: eflags = (eflags & ~(CC_Z | CC_P | CC_C)) | fcomi_ccval[ret + 1]; ! 3654: CC_SRC = eflags; ! 3655: } ! 3656: ! 3657: void helper_fucomi_ST0_FT0(void) ! 3658: { ! 3659: int eflags; ! 3660: int ret; ! 3661: ! 3662: ret = floatx_compare_quiet(ST0, FT0, &env->fp_status); ! 3663: eflags = helper_cc_compute_all(CC_OP); ! 3664: eflags = (eflags & ~(CC_Z | CC_P | CC_C)) | fcomi_ccval[ret + 1]; ! 3665: CC_SRC = eflags; ! 3666: } ! 3667: ! 3668: void helper_fadd_ST0_FT0(void) ! 3669: { ! 3670: ST0 += FT0; ! 3671: } ! 3672: ! 3673: void helper_fmul_ST0_FT0(void) ! 3674: { ! 3675: ST0 *= FT0; ! 3676: } ! 3677: ! 3678: void helper_fsub_ST0_FT0(void) ! 3679: { ! 3680: ST0 -= FT0; ! 3681: } ! 3682: ! 3683: void helper_fsubr_ST0_FT0(void) ! 3684: { ! 3685: ST0 = FT0 - ST0; ! 3686: } ! 3687: ! 3688: void helper_fdiv_ST0_FT0(void) ! 3689: { ! 3690: ST0 = helper_fdiv(ST0, FT0); ! 3691: } ! 3692: ! 3693: void helper_fdivr_ST0_FT0(void) ! 3694: { ! 3695: ST0 = helper_fdiv(FT0, ST0); ! 3696: } ! 3697: ! 3698: /* fp operations between STN and ST0 */ ! 3699: ! 3700: void helper_fadd_STN_ST0(int st_index) ! 3701: { ! 3702: ST(st_index) += ST0; ! 3703: } ! 3704: ! 3705: void helper_fmul_STN_ST0(int st_index) ! 3706: { ! 3707: ST(st_index) *= ST0; ! 3708: } ! 3709: ! 3710: void helper_fsub_STN_ST0(int st_index) ! 3711: { ! 3712: ST(st_index) -= ST0; ! 3713: } ! 3714: ! 3715: void helper_fsubr_STN_ST0(int st_index) ! 3716: { ! 3717: CPU86_LDouble *p; ! 3718: p = &ST(st_index); ! 3719: *p = ST0 - *p; ! 3720: } ! 3721: ! 3722: void helper_fdiv_STN_ST0(int st_index) ! 3723: { ! 3724: CPU86_LDouble *p; ! 3725: p = &ST(st_index); ! 3726: *p = helper_fdiv(*p, ST0); ! 3727: } ! 3728: ! 3729: void helper_fdivr_STN_ST0(int st_index) ! 3730: { ! 3731: CPU86_LDouble *p; ! 3732: p = &ST(st_index); ! 3733: *p = helper_fdiv(ST0, *p); ! 3734: } ! 3735: ! 3736: /* misc FPU operations */ ! 3737: void helper_fchs_ST0(void) ! 3738: { ! 3739: ST0 = floatx_chs(ST0); ! 3740: } ! 3741: ! 3742: void helper_fabs_ST0(void) ! 3743: { ! 3744: ST0 = floatx_abs(ST0); ! 3745: } ! 3746: ! 3747: void helper_fld1_ST0(void) ! 3748: { ! 3749: ST0 = f15rk[1]; ! 3750: } ! 3751: ! 3752: void helper_fldl2t_ST0(void) ! 3753: { ! 3754: ST0 = f15rk[6]; ! 3755: } ! 3756: ! 3757: void helper_fldl2e_ST0(void) ! 3758: { ! 3759: ST0 = f15rk[5]; ! 3760: } ! 3761: ! 3762: void helper_fldpi_ST0(void) ! 3763: { ! 3764: ST0 = f15rk[2]; ! 3765: } ! 3766: ! 3767: void helper_fldlg2_ST0(void) ! 3768: { ! 3769: ST0 = f15rk[3]; ! 3770: } ! 3771: ! 3772: void helper_fldln2_ST0(void) ! 3773: { ! 3774: ST0 = f15rk[4]; ! 3775: } ! 3776: ! 3777: void helper_fldz_ST0(void) ! 3778: { ! 3779: ST0 = f15rk[0]; ! 3780: } ! 3781: ! 3782: void helper_fldz_FT0(void) ! 3783: { ! 3784: FT0 = f15rk[0]; ! 3785: } ! 3786: ! 3787: uint32_t helper_fnstsw(void) ! 3788: { ! 3789: return (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; ! 3790: } ! 3791: ! 3792: uint32_t helper_fnstcw(void) ! 3793: { ! 3794: return env->fpuc; ! 3795: } ! 3796: ! 3797: static void update_fp_status(void) ! 3798: { ! 3799: int rnd_type; ! 3800: ! 3801: /* set rounding mode */ ! 3802: switch(env->fpuc & RC_MASK) { ! 3803: default: ! 3804: case RC_NEAR: ! 3805: rnd_type = float_round_nearest_even; ! 3806: break; ! 3807: case RC_DOWN: ! 3808: rnd_type = float_round_down; ! 3809: break; ! 3810: case RC_UP: ! 3811: rnd_type = float_round_up; ! 3812: break; ! 3813: case RC_CHOP: ! 3814: rnd_type = float_round_to_zero; ! 3815: break; ! 3816: } ! 3817: set_float_rounding_mode(rnd_type, &env->fp_status); ! 3818: #ifdef FLOATX80 ! 3819: switch((env->fpuc >> 8) & 3) { ! 3820: case 0: ! 3821: rnd_type = 32; ! 3822: break; ! 3823: case 2: ! 3824: rnd_type = 64; ! 3825: break; ! 3826: case 3: ! 3827: default: ! 3828: rnd_type = 80; ! 3829: break; ! 3830: } ! 3831: set_floatx80_rounding_precision(rnd_type, &env->fp_status); ! 3832: #endif ! 3833: } ! 3834: ! 3835: void helper_fldcw(uint32_t val) ! 3836: { ! 3837: env->fpuc = val; ! 3838: update_fp_status(); ! 3839: } ! 3840: ! 3841: void helper_fclex(void) ! 3842: { ! 3843: env->fpus &= 0x7f00; ! 3844: } ! 3845: ! 3846: void helper_fwait(void) ! 3847: { ! 3848: if (env->fpus & FPUS_SE) ! 3849: fpu_raise_exception(); ! 3850: } ! 3851: ! 3852: void helper_fninit(void) ! 3853: { ! 3854: env->fpus = 0; ! 3855: env->fpstt = 0; ! 3856: env->fpuc = 0x37f; ! 3857: env->fptags[0] = 1; ! 3858: env->fptags[1] = 1; ! 3859: env->fptags[2] = 1; ! 3860: env->fptags[3] = 1; ! 3861: env->fptags[4] = 1; ! 3862: env->fptags[5] = 1; ! 3863: env->fptags[6] = 1; ! 3864: env->fptags[7] = 1; ! 3865: } ! 3866: ! 3867: /* BCD ops */ ! 3868: ! 3869: void helper_fbld_ST0(target_ulong ptr) ! 3870: { ! 3871: CPU86_LDouble tmp; ! 3872: uint64_t val; ! 3873: unsigned int v; ! 3874: int i; ! 3875: ! 3876: val = 0; ! 3877: for(i = 8; i >= 0; i--) { ! 3878: v = ldub(ptr + i); ! 3879: val = (val * 100) + ((v >> 4) * 10) + (v & 0xf); ! 3880: } ! 3881: tmp = val; ! 3882: if (ldub(ptr + 9) & 0x80) ! 3883: tmp = -tmp; ! 3884: fpush(); ! 3885: ST0 = tmp; ! 3886: } ! 3887: ! 3888: void helper_fbst_ST0(target_ulong ptr) ! 3889: { ! 3890: int v; ! 3891: target_ulong mem_ref, mem_end; ! 3892: int64_t val; ! 3893: ! 3894: val = floatx_to_int64(ST0, &env->fp_status); ! 3895: mem_ref = ptr; ! 3896: mem_end = mem_ref + 9; ! 3897: if (val < 0) { ! 3898: stb(mem_end, 0x80); ! 3899: val = -val; ! 3900: } else { ! 3901: stb(mem_end, 0x00); ! 3902: } ! 3903: while (mem_ref < mem_end) { ! 3904: if (val == 0) ! 3905: break; ! 3906: v = val % 100; ! 3907: val = val / 100; ! 3908: v = ((v / 10) << 4) | (v % 10); ! 3909: stb(mem_ref++, v); ! 3910: } ! 3911: while (mem_ref < mem_end) { ! 3912: stb(mem_ref++, 0); ! 3913: } ! 3914: } ! 3915: ! 3916: void helper_f2xm1(void) ! 3917: { ! 3918: ST0 = pow(2.0,ST0) - 1.0; ! 3919: } ! 3920: ! 3921: void helper_fyl2x(void) ! 3922: { ! 3923: CPU86_LDouble fptemp; ! 3924: ! 3925: fptemp = ST0; ! 3926: if (fptemp>0.0){ ! 3927: fptemp = log(fptemp)/log(2.0); /* log2(ST) */ ! 3928: ST1 *= fptemp; ! 3929: fpop(); ! 3930: } else { ! 3931: env->fpus &= (~0x4700); ! 3932: env->fpus |= 0x400; ! 3933: } ! 3934: } ! 3935: ! 3936: void helper_fptan(void) ! 3937: { ! 3938: CPU86_LDouble fptemp; ! 3939: ! 3940: fptemp = ST0; ! 3941: if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { ! 3942: env->fpus |= 0x400; ! 3943: } else { ! 3944: ST0 = tan(fptemp); ! 3945: fpush(); ! 3946: ST0 = 1.0; ! 3947: env->fpus &= (~0x400); /* C2 <-- 0 */ ! 3948: /* the above code is for |arg| < 2**52 only */ ! 3949: } ! 3950: } ! 3951: ! 3952: void helper_fpatan(void) ! 3953: { ! 3954: CPU86_LDouble fptemp, fpsrcop; ! 3955: ! 3956: fpsrcop = ST1; ! 3957: fptemp = ST0; ! 3958: ST1 = atan2(fpsrcop,fptemp); ! 3959: fpop(); ! 3960: } ! 3961: ! 3962: void helper_fxtract(void) ! 3963: { ! 3964: CPU86_LDoubleU temp; ! 3965: unsigned int expdif; ! 3966: ! 3967: temp.d = ST0; ! 3968: expdif = EXPD(temp) - EXPBIAS; ! 3969: /*DP exponent bias*/ ! 3970: ST0 = expdif; ! 3971: fpush(); ! 3972: BIASEXPONENT(temp); ! 3973: ST0 = temp.d; ! 3974: } ! 3975: ! 3976: void helper_fprem1(void) ! 3977: { ! 3978: CPU86_LDouble dblq, fpsrcop, fptemp; ! 3979: CPU86_LDoubleU fpsrcop1, fptemp1; ! 3980: int expdif; ! 3981: signed long long int q; ! 3982: ! 3983: if (isinf(ST0) || isnan(ST0) || isnan(ST1) || (ST1 == 0.0)) { ! 3984: ST0 = 0.0 / 0.0; /* NaN */ ! 3985: env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ ! 3986: return; ! 3987: } ! 3988: ! 3989: fpsrcop = ST0; ! 3990: fptemp = ST1; ! 3991: fpsrcop1.d = fpsrcop; ! 3992: fptemp1.d = fptemp; ! 3993: expdif = EXPD(fpsrcop1) - EXPD(fptemp1); ! 3994: ! 3995: if (expdif < 0) { ! 3996: /* optimisation? taken from the AMD docs */ ! 3997: env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ ! 3998: /* ST0 is unchanged */ ! 3999: return; ! 4000: } ! 4001: ! 4002: if (expdif < 53) { ! 4003: dblq = fpsrcop / fptemp; ! 4004: /* round dblq towards nearest integer */ ! 4005: dblq = rint(dblq); ! 4006: ST0 = fpsrcop - fptemp * dblq; ! 4007: ! 4008: /* convert dblq to q by truncating towards zero */ ! 4009: if (dblq < 0.0) ! 4010: q = (signed long long int)(-dblq); ! 4011: else ! 4012: q = (signed long long int)dblq; ! 4013: ! 4014: env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ ! 4015: /* (C0,C3,C1) <-- (q2,q1,q0) */ ! 4016: env->fpus |= (q & 0x4) << (8 - 2); /* (C0) <-- q2 */ ! 4017: env->fpus |= (q & 0x2) << (14 - 1); /* (C3) <-- q1 */ ! 4018: env->fpus |= (q & 0x1) << (9 - 0); /* (C1) <-- q0 */ ! 4019: } else { ! 4020: env->fpus |= 0x400; /* C2 <-- 1 */ ! 4021: fptemp = pow(2.0, expdif - 50); ! 4022: fpsrcop = (ST0 / ST1) / fptemp; ! 4023: /* fpsrcop = integer obtained by chopping */ ! 4024: fpsrcop = (fpsrcop < 0.0) ? ! 4025: -(floor(fabs(fpsrcop))) : floor(fpsrcop); ! 4026: ST0 -= (ST1 * fpsrcop * fptemp); ! 4027: } ! 4028: } ! 4029: ! 4030: void helper_fprem(void) ! 4031: { ! 4032: CPU86_LDouble dblq, fpsrcop, fptemp; ! 4033: CPU86_LDoubleU fpsrcop1, fptemp1; ! 4034: int expdif; ! 4035: signed long long int q; ! 4036: ! 4037: if (isinf(ST0) || isnan(ST0) || isnan(ST1) || (ST1 == 0.0)) { ! 4038: ST0 = 0.0 / 0.0; /* NaN */ ! 4039: env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ ! 4040: return; ! 4041: } ! 4042: ! 4043: fpsrcop = (CPU86_LDouble)ST0; ! 4044: fptemp = (CPU86_LDouble)ST1; ! 4045: fpsrcop1.d = fpsrcop; ! 4046: fptemp1.d = fptemp; ! 4047: expdif = EXPD(fpsrcop1) - EXPD(fptemp1); ! 4048: ! 4049: if (expdif < 0) { ! 4050: /* optimisation? taken from the AMD docs */ ! 4051: env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ ! 4052: /* ST0 is unchanged */ ! 4053: return; ! 4054: } ! 4055: ! 4056: if ( expdif < 53 ) { ! 4057: dblq = fpsrcop/*ST0*/ / fptemp/*ST1*/; ! 4058: /* round dblq towards zero */ ! 4059: dblq = (dblq < 0.0) ? ceil(dblq) : floor(dblq); ! 4060: ST0 = fpsrcop/*ST0*/ - fptemp * dblq; ! 4061: ! 4062: /* convert dblq to q by truncating towards zero */ ! 4063: if (dblq < 0.0) ! 4064: q = (signed long long int)(-dblq); ! 4065: else ! 4066: q = (signed long long int)dblq; ! 4067: ! 4068: env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ ! 4069: /* (C0,C3,C1) <-- (q2,q1,q0) */ ! 4070: env->fpus |= (q & 0x4) << (8 - 2); /* (C0) <-- q2 */ ! 4071: env->fpus |= (q & 0x2) << (14 - 1); /* (C3) <-- q1 */ ! 4072: env->fpus |= (q & 0x1) << (9 - 0); /* (C1) <-- q0 */ ! 4073: } else { ! 4074: int N = 32 + (expdif % 32); /* as per AMD docs */ ! 4075: env->fpus |= 0x400; /* C2 <-- 1 */ ! 4076: fptemp = pow(2.0, (double)(expdif - N)); ! 4077: fpsrcop = (ST0 / ST1) / fptemp; ! 4078: /* fpsrcop = integer obtained by chopping */ ! 4079: fpsrcop = (fpsrcop < 0.0) ? ! 4080: -(floor(fabs(fpsrcop))) : floor(fpsrcop); ! 4081: ST0 -= (ST1 * fpsrcop * fptemp); ! 4082: } ! 4083: } ! 4084: ! 4085: void helper_fyl2xp1(void) ! 4086: { ! 4087: CPU86_LDouble fptemp; ! 4088: ! 4089: fptemp = ST0; ! 4090: if ((fptemp+1.0)>0.0) { ! 4091: fptemp = log(fptemp+1.0) / log(2.0); /* log2(ST+1.0) */ ! 4092: ST1 *= fptemp; ! 4093: fpop(); ! 4094: } else { ! 4095: env->fpus &= (~0x4700); ! 4096: env->fpus |= 0x400; ! 4097: } ! 4098: } ! 4099: ! 4100: void helper_fsqrt(void) ! 4101: { ! 4102: CPU86_LDouble fptemp; ! 4103: ! 4104: fptemp = ST0; ! 4105: if (fptemp<0.0) { ! 4106: env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ ! 4107: env->fpus |= 0x400; ! 4108: } ! 4109: ST0 = sqrt(fptemp); ! 4110: } ! 4111: ! 4112: void helper_fsincos(void) ! 4113: { ! 4114: CPU86_LDouble fptemp; ! 4115: ! 4116: fptemp = ST0; ! 4117: if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { ! 4118: env->fpus |= 0x400; ! 4119: } else { ! 4120: ST0 = sin(fptemp); ! 4121: fpush(); ! 4122: ST0 = cos(fptemp); ! 4123: env->fpus &= (~0x400); /* C2 <-- 0 */ ! 4124: /* the above code is for |arg| < 2**63 only */ ! 4125: } ! 4126: } ! 4127: ! 4128: void helper_frndint(void) ! 4129: { ! 4130: ST0 = floatx_round_to_int(ST0, &env->fp_status); ! 4131: } ! 4132: ! 4133: void helper_fscale(void) ! 4134: { ! 4135: ST0 = ldexp (ST0, (int)(ST1)); ! 4136: } ! 4137: ! 4138: void helper_fsin(void) ! 4139: { ! 4140: CPU86_LDouble fptemp; ! 4141: ! 4142: fptemp = ST0; ! 4143: if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { ! 4144: env->fpus |= 0x400; ! 4145: } else { ! 4146: ST0 = sin(fptemp); ! 4147: env->fpus &= (~0x400); /* C2 <-- 0 */ ! 4148: /* the above code is for |arg| < 2**53 only */ ! 4149: } ! 4150: } ! 4151: ! 4152: void helper_fcos(void) ! 4153: { ! 4154: CPU86_LDouble fptemp; ! 4155: ! 4156: fptemp = ST0; ! 4157: if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { ! 4158: env->fpus |= 0x400; ! 4159: } else { ! 4160: ST0 = cos(fptemp); ! 4161: env->fpus &= (~0x400); /* C2 <-- 0 */ ! 4162: /* the above code is for |arg5 < 2**63 only */ ! 4163: } ! 4164: } ! 4165: ! 4166: void helper_fxam_ST0(void) ! 4167: { ! 4168: CPU86_LDoubleU temp; ! 4169: int expdif; ! 4170: ! 4171: temp.d = ST0; ! 4172: ! 4173: env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ ! 4174: if (SIGND(temp)) ! 4175: env->fpus |= 0x200; /* C1 <-- 1 */ ! 4176: ! 4177: /* XXX: test fptags too */ ! 4178: expdif = EXPD(temp); ! 4179: if (expdif == MAXEXPD) { ! 4180: #ifdef USE_X86LDOUBLE ! 4181: if (MANTD(temp) == 0x8000000000000000ULL) ! 4182: #else ! 4183: if (MANTD(temp) == 0) ! 4184: #endif ! 4185: env->fpus |= 0x500 /*Infinity*/; ! 4186: else ! 4187: env->fpus |= 0x100 /*NaN*/; ! 4188: } else if (expdif == 0) { ! 4189: if (MANTD(temp) == 0) ! 4190: env->fpus |= 0x4000 /*Zero*/; ! 4191: else ! 4192: env->fpus |= 0x4400 /*Denormal*/; ! 4193: } else { ! 4194: env->fpus |= 0x400; ! 4195: } ! 4196: } ! 4197: ! 4198: void helper_fstenv(target_ulong ptr, int data32) ! 4199: { ! 4200: int fpus, fptag, exp, i; ! 4201: uint64_t mant; ! 4202: CPU86_LDoubleU tmp; ! 4203: ! 4204: fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; ! 4205: fptag = 0; ! 4206: for (i=7; i>=0; i--) { ! 4207: fptag <<= 2; ! 4208: if (env->fptags[i]) { ! 4209: fptag |= 3; ! 4210: } else { ! 4211: tmp.d = env->fpregs[i].d; ! 4212: exp = EXPD(tmp); ! 4213: mant = MANTD(tmp); ! 4214: if (exp == 0 && mant == 0) { ! 4215: /* zero */ ! 4216: fptag |= 1; ! 4217: } else if (exp == 0 || exp == MAXEXPD ! 4218: #ifdef USE_X86LDOUBLE ! 4219: || (mant & (1LL << 63)) == 0 ! 4220: #endif ! 4221: ) { ! 4222: /* NaNs, infinity, denormal */ ! 4223: fptag |= 2; ! 4224: } ! 4225: } ! 4226: } ! 4227: if (data32) { ! 4228: /* 32 bit */ ! 4229: stl(ptr, env->fpuc); ! 4230: stl(ptr + 4, fpus); ! 4231: stl(ptr + 8, fptag); ! 4232: stl(ptr + 12, 0); /* fpip */ ! 4233: stl(ptr + 16, 0); /* fpcs */ ! 4234: stl(ptr + 20, 0); /* fpoo */ ! 4235: stl(ptr + 24, 0); /* fpos */ ! 4236: } else { ! 4237: /* 16 bit */ ! 4238: stw(ptr, env->fpuc); ! 4239: stw(ptr + 2, fpus); ! 4240: stw(ptr + 4, fptag); ! 4241: stw(ptr + 6, 0); ! 4242: stw(ptr + 8, 0); ! 4243: stw(ptr + 10, 0); ! 4244: stw(ptr + 12, 0); ! 4245: } ! 4246: } ! 4247: ! 4248: void helper_fldenv(target_ulong ptr, int data32) ! 4249: { ! 4250: int i, fpus, fptag; ! 4251: ! 4252: if (data32) { ! 4253: env->fpuc = lduw(ptr); ! 4254: fpus = lduw(ptr + 4); ! 4255: fptag = lduw(ptr + 8); ! 4256: } ! 4257: else { ! 4258: env->fpuc = lduw(ptr); ! 4259: fpus = lduw(ptr + 2); ! 4260: fptag = lduw(ptr + 4); ! 4261: } ! 4262: env->fpstt = (fpus >> 11) & 7; ! 4263: env->fpus = fpus & ~0x3800; ! 4264: for(i = 0;i < 8; i++) { ! 4265: env->fptags[i] = ((fptag & 3) == 3); ! 4266: fptag >>= 2; ! 4267: } ! 4268: } ! 4269: ! 4270: void helper_fsave(target_ulong ptr, int data32) ! 4271: { ! 4272: CPU86_LDouble tmp; ! 4273: int i; ! 4274: ! 4275: helper_fstenv(ptr, data32); ! 4276: ! 4277: ptr += (14 << data32); ! 4278: for(i = 0;i < 8; i++) { ! 4279: tmp = ST(i); ! 4280: helper_fstt(tmp, ptr); ! 4281: ptr += 10; ! 4282: } ! 4283: ! 4284: /* fninit */ ! 4285: env->fpus = 0; ! 4286: env->fpstt = 0; ! 4287: env->fpuc = 0x37f; ! 4288: env->fptags[0] = 1; ! 4289: env->fptags[1] = 1; ! 4290: env->fptags[2] = 1; ! 4291: env->fptags[3] = 1; ! 4292: env->fptags[4] = 1; ! 4293: env->fptags[5] = 1; ! 4294: env->fptags[6] = 1; ! 4295: env->fptags[7] = 1; ! 4296: } ! 4297: ! 4298: void helper_frstor(target_ulong ptr, int data32) ! 4299: { ! 4300: CPU86_LDouble tmp; ! 4301: int i; ! 4302: ! 4303: helper_fldenv(ptr, data32); ! 4304: ptr += (14 << data32); ! 4305: ! 4306: for(i = 0;i < 8; i++) { ! 4307: tmp = helper_fldt(ptr); ! 4308: ST(i) = tmp; ! 4309: ptr += 10; ! 4310: } ! 4311: } ! 4312: ! 4313: void helper_fxsave(target_ulong ptr, int data64) ! 4314: { ! 4315: int fpus, fptag, i, nb_xmm_regs; ! 4316: CPU86_LDouble tmp; ! 4317: target_ulong addr; ! 4318: ! 4319: fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; ! 4320: fptag = 0; ! 4321: for(i = 0; i < 8; i++) { ! 4322: fptag |= (env->fptags[i] << i); ! 4323: } ! 4324: stw(ptr, env->fpuc); ! 4325: stw(ptr + 2, fpus); ! 4326: stw(ptr + 4, fptag ^ 0xff); ! 4327: #ifdef TARGET_X86_64 ! 4328: if (data64) { ! 4329: stq(ptr + 0x08, 0); /* rip */ ! 4330: stq(ptr + 0x10, 0); /* rdp */ ! 4331: } else ! 4332: #endif ! 4333: { ! 4334: stl(ptr + 0x08, 0); /* eip */ ! 4335: stl(ptr + 0x0c, 0); /* sel */ ! 4336: stl(ptr + 0x10, 0); /* dp */ ! 4337: stl(ptr + 0x14, 0); /* sel */ ! 4338: } ! 4339: ! 4340: addr = ptr + 0x20; ! 4341: for(i = 0;i < 8; i++) { ! 4342: tmp = ST(i); ! 4343: helper_fstt(tmp, addr); ! 4344: addr += 16; ! 4345: } ! 4346: ! 4347: if (env->cr[4] & CR4_OSFXSR_MASK) { ! 4348: /* XXX: finish it */ ! 4349: stl(ptr + 0x18, env->mxcsr); /* mxcsr */ ! 4350: stl(ptr + 0x1c, 0x0000ffff); /* mxcsr_mask */ ! 4351: if (env->hflags & HF_CS64_MASK) ! 4352: nb_xmm_regs = 16; ! 4353: else ! 4354: nb_xmm_regs = 8; ! 4355: addr = ptr + 0xa0; ! 4356: /* Fast FXSAVE leaves out the XMM registers */ ! 4357: if (!(env->efer & MSR_EFER_FFXSR) ! 4358: || (env->hflags & HF_CPL_MASK) ! 4359: || !(env->hflags & HF_LMA_MASK)) { ! 4360: for(i = 0; i < nb_xmm_regs; i++) { ! 4361: stq(addr, env->xmm_regs[i].XMM_Q(0)); ! 4362: stq(addr + 8, env->xmm_regs[i].XMM_Q(1)); ! 4363: addr += 16; ! 4364: } ! 4365: } ! 4366: } ! 4367: } ! 4368: ! 4369: void helper_fxrstor(target_ulong ptr, int data64) ! 4370: { ! 4371: int i, fpus, fptag, nb_xmm_regs; ! 4372: CPU86_LDouble tmp; ! 4373: target_ulong addr; ! 4374: ! 4375: env->fpuc = lduw(ptr); ! 4376: fpus = lduw(ptr + 2); ! 4377: fptag = lduw(ptr + 4); ! 4378: env->fpstt = (fpus >> 11) & 7; ! 4379: env->fpus = fpus & ~0x3800; ! 4380: fptag ^= 0xff; ! 4381: for(i = 0;i < 8; i++) { ! 4382: env->fptags[i] = ((fptag >> i) & 1); ! 4383: } ! 4384: ! 4385: addr = ptr + 0x20; ! 4386: for(i = 0;i < 8; i++) { ! 4387: tmp = helper_fldt(addr); ! 4388: ST(i) = tmp; ! 4389: addr += 16; ! 4390: } ! 4391: ! 4392: if (env->cr[4] & CR4_OSFXSR_MASK) { ! 4393: /* XXX: finish it */ ! 4394: env->mxcsr = ldl(ptr + 0x18); ! 4395: //ldl(ptr + 0x1c); ! 4396: if (env->hflags & HF_CS64_MASK) ! 4397: nb_xmm_regs = 16; ! 4398: else ! 4399: nb_xmm_regs = 8; ! 4400: addr = ptr + 0xa0; ! 4401: /* Fast FXRESTORE leaves out the XMM registers */ ! 4402: if (!(env->efer & MSR_EFER_FFXSR) ! 4403: || (env->hflags & HF_CPL_MASK) ! 4404: || !(env->hflags & HF_LMA_MASK)) { ! 4405: for(i = 0; i < nb_xmm_regs; i++) { ! 4406: env->xmm_regs[i].XMM_Q(0) = ldq(addr); ! 4407: env->xmm_regs[i].XMM_Q(1) = ldq(addr + 8); ! 4408: addr += 16; ! 4409: } ! 4410: } ! 4411: } ! 4412: } ! 4413: ! 4414: #ifndef USE_X86LDOUBLE ! 4415: ! 4416: void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, CPU86_LDouble f) ! 4417: { ! 4418: CPU86_LDoubleU temp; ! 4419: int e; ! 4420: ! 4421: temp.d = f; ! 4422: /* mantissa */ ! 4423: *pmant = (MANTD(temp) << 11) | (1LL << 63); ! 4424: /* exponent + sign */ ! 4425: e = EXPD(temp) - EXPBIAS + 16383; ! 4426: e |= SIGND(temp) >> 16; ! 4427: *pexp = e; ! 4428: } ! 4429: ! 4430: CPU86_LDouble cpu_set_fp80(uint64_t mant, uint16_t upper) ! 4431: { ! 4432: CPU86_LDoubleU temp; ! 4433: int e; ! 4434: uint64_t ll; ! 4435: ! 4436: /* XXX: handle overflow ? */ ! 4437: e = (upper & 0x7fff) - 16383 + EXPBIAS; /* exponent */ ! 4438: e |= (upper >> 4) & 0x800; /* sign */ ! 4439: ll = (mant >> 11) & ((1LL << 52) - 1); ! 4440: #ifdef __arm__ ! 4441: temp.l.upper = (e << 20) | (ll >> 32); ! 4442: temp.l.lower = ll; ! 4443: #else ! 4444: temp.ll = ll | ((uint64_t)e << 52); ! 4445: #endif ! 4446: return temp.d; ! 4447: } ! 4448: ! 4449: #else ! 4450: ! 4451: void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, CPU86_LDouble f) ! 4452: { ! 4453: CPU86_LDoubleU temp; ! 4454: ! 4455: temp.d = f; ! 4456: *pmant = temp.l.lower; ! 4457: *pexp = temp.l.upper; ! 4458: } ! 4459: ! 4460: CPU86_LDouble cpu_set_fp80(uint64_t mant, uint16_t upper) ! 4461: { ! 4462: CPU86_LDoubleU temp; ! 4463: ! 4464: temp.l.upper = upper; ! 4465: temp.l.lower = mant; ! 4466: return temp.d; ! 4467: } ! 4468: #endif ! 4469: ! 4470: #ifdef TARGET_X86_64 ! 4471: ! 4472: //#define DEBUG_MULDIV ! 4473: ! 4474: static void add128(uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b) ! 4475: { ! 4476: *plow += a; ! 4477: /* carry test */ ! 4478: if (*plow < a) ! 4479: (*phigh)++; ! 4480: *phigh += b; ! 4481: } ! 4482: ! 4483: static void neg128(uint64_t *plow, uint64_t *phigh) ! 4484: { ! 4485: *plow = ~ *plow; ! 4486: *phigh = ~ *phigh; ! 4487: add128(plow, phigh, 1, 0); ! 4488: } ! 4489: ! 4490: /* return TRUE if overflow */ ! 4491: static int div64(uint64_t *plow, uint64_t *phigh, uint64_t b) ! 4492: { ! 4493: uint64_t q, r, a1, a0; ! 4494: int i, qb, ab; ! 4495: ! 4496: a0 = *plow; ! 4497: a1 = *phigh; ! 4498: if (a1 == 0) { ! 4499: q = a0 / b; ! 4500: r = a0 % b; ! 4501: *plow = q; ! 4502: *phigh = r; ! 4503: } else { ! 4504: if (a1 >= b) ! 4505: return 1; ! 4506: /* XXX: use a better algorithm */ ! 4507: for(i = 0; i < 64; i++) { ! 4508: ab = a1 >> 63; ! 4509: a1 = (a1 << 1) | (a0 >> 63); ! 4510: if (ab || a1 >= b) { ! 4511: a1 -= b; ! 4512: qb = 1; ! 4513: } else { ! 4514: qb = 0; ! 4515: } ! 4516: a0 = (a0 << 1) | qb; ! 4517: } ! 4518: #if defined(DEBUG_MULDIV) ! 4519: printf("div: 0x%016" PRIx64 "%016" PRIx64 " / 0x%016" PRIx64 ": q=0x%016" PRIx64 " r=0x%016" PRIx64 "\n", ! 4520: *phigh, *plow, b, a0, a1); ! 4521: #endif ! 4522: *plow = a0; ! 4523: *phigh = a1; ! 4524: } ! 4525: return 0; ! 4526: } ! 4527: ! 4528: /* return TRUE if overflow */ ! 4529: static int idiv64(uint64_t *plow, uint64_t *phigh, int64_t b) ! 4530: { ! 4531: int sa, sb; ! 4532: sa = ((int64_t)*phigh < 0); ! 4533: if (sa) ! 4534: neg128(plow, phigh); ! 4535: sb = (b < 0); ! 4536: if (sb) ! 4537: b = -b; ! 4538: if (div64(plow, phigh, b) != 0) ! 4539: return 1; ! 4540: if (sa ^ sb) { ! 4541: if (*plow > (1ULL << 63)) ! 4542: return 1; ! 4543: *plow = - *plow; ! 4544: } else { ! 4545: if (*plow >= (1ULL << 63)) ! 4546: return 1; ! 4547: } ! 4548: if (sa) ! 4549: *phigh = - *phigh; ! 4550: return 0; ! 4551: } ! 4552: ! 4553: void helper_mulq_EAX_T0(target_ulong t0) ! 4554: { ! 4555: uint64_t r0, r1; ! 4556: ! 4557: mulu64(&r0, &r1, EAX, t0); ! 4558: EAX = r0; ! 4559: EDX = r1; ! 4560: CC_DST = r0; ! 4561: CC_SRC = r1; ! 4562: } ! 4563: ! 4564: void helper_imulq_EAX_T0(target_ulong t0) ! 4565: { ! 4566: uint64_t r0, r1; ! 4567: ! 4568: muls64(&r0, &r1, EAX, t0); ! 4569: EAX = r0; ! 4570: EDX = r1; ! 4571: CC_DST = r0; ! 4572: CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63)); ! 4573: } ! 4574: ! 4575: target_ulong helper_imulq_T0_T1(target_ulong t0, target_ulong t1) ! 4576: { ! 4577: uint64_t r0, r1; ! 4578: ! 4579: muls64(&r0, &r1, t0, t1); ! 4580: CC_DST = r0; ! 4581: CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63)); ! 4582: return r0; ! 4583: } ! 4584: ! 4585: void helper_divq_EAX(target_ulong t0) ! 4586: { ! 4587: uint64_t r0, r1; ! 4588: if (t0 == 0) { ! 4589: raise_exception(EXCP00_DIVZ); ! 4590: } ! 4591: r0 = EAX; ! 4592: r1 = EDX; ! 4593: if (div64(&r0, &r1, t0)) ! 4594: raise_exception(EXCP00_DIVZ); ! 4595: EAX = r0; ! 4596: EDX = r1; ! 4597: } ! 4598: ! 4599: void helper_idivq_EAX(target_ulong t0) ! 4600: { ! 4601: uint64_t r0, r1; ! 4602: if (t0 == 0) { ! 4603: raise_exception(EXCP00_DIVZ); ! 4604: } ! 4605: r0 = EAX; ! 4606: r1 = EDX; ! 4607: if (idiv64(&r0, &r1, t0)) ! 4608: raise_exception(EXCP00_DIVZ); ! 4609: EAX = r0; ! 4610: EDX = r1; ! 4611: } ! 4612: #endif ! 4613: ! 4614: static void do_hlt(void) ! 4615: { ! 4616: env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */ ! 4617: env->halted = 1; ! 4618: env->exception_index = EXCP_HLT; ! 4619: cpu_loop_exit(); ! 4620: } ! 4621: ! 4622: void helper_hlt(int next_eip_addend) ! 4623: { ! 4624: helper_svm_check_intercept_param(SVM_EXIT_HLT, 0); ! 4625: EIP += next_eip_addend; ! 4626: ! 4627: do_hlt(); ! 4628: } ! 4629: ! 4630: void helper_monitor(target_ulong ptr) ! 4631: { ! 4632: if ((uint32_t)ECX != 0) ! 4633: raise_exception(EXCP0D_GPF); ! 4634: /* XXX: store address ? */ ! 4635: helper_svm_check_intercept_param(SVM_EXIT_MONITOR, 0); ! 4636: } ! 4637: ! 4638: void helper_mwait(int next_eip_addend) ! 4639: { ! 4640: if ((uint32_t)ECX != 0) ! 4641: raise_exception(EXCP0D_GPF); ! 4642: helper_svm_check_intercept_param(SVM_EXIT_MWAIT, 0); ! 4643: EIP += next_eip_addend; ! 4644: ! 4645: /* XXX: not complete but not completely erroneous */ ! 4646: if (env->cpu_index != 0 || env->next_cpu != NULL) { ! 4647: /* more than one CPU: do not sleep because another CPU may ! 4648: wake this one */ ! 4649: } else { ! 4650: do_hlt(); ! 4651: } ! 4652: } ! 4653: ! 4654: void helper_debug(void) ! 4655: { ! 4656: env->exception_index = EXCP_DEBUG; ! 4657: cpu_loop_exit(); ! 4658: } ! 4659: ! 4660: void helper_raise_interrupt(int intno, int next_eip_addend) ! 4661: { ! 4662: raise_interrupt(intno, 1, 0, next_eip_addend); ! 4663: } ! 4664: ! 4665: void helper_raise_exception(int exception_index) ! 4666: { ! 4667: raise_exception(exception_index); ! 4668: } ! 4669: ! 4670: void helper_cli(void) ! 4671: { ! 4672: env->eflags &= ~IF_MASK; ! 4673: } ! 4674: ! 4675: void helper_sti(void) ! 4676: { ! 4677: env->eflags |= IF_MASK; ! 4678: } ! 4679: ! 4680: #if 0 ! 4681: /* vm86plus instructions */ ! 4682: void helper_cli_vm(void) ! 4683: { ! 4684: env->eflags &= ~VIF_MASK; ! 4685: } ! 4686: ! 4687: void helper_sti_vm(void) ! 4688: { ! 4689: env->eflags |= VIF_MASK; ! 4690: if (env->eflags & VIP_MASK) { ! 4691: raise_exception(EXCP0D_GPF); ! 4692: } ! 4693: } ! 4694: #endif ! 4695: ! 4696: void helper_set_inhibit_irq(void) ! 4697: { ! 4698: env->hflags |= HF_INHIBIT_IRQ_MASK; ! 4699: } ! 4700: ! 4701: void helper_reset_inhibit_irq(void) ! 4702: { ! 4703: env->hflags &= ~HF_INHIBIT_IRQ_MASK; ! 4704: } ! 4705: ! 4706: void helper_boundw(target_ulong a0, int v) ! 4707: { ! 4708: int low, high; ! 4709: low = ldsw(a0); ! 4710: high = ldsw(a0 + 2); ! 4711: v = (int16_t)v; ! 4712: if (v < low || v > high) { ! 4713: raise_exception(EXCP05_BOUND); ! 4714: } ! 4715: } ! 4716: ! 4717: void helper_boundl(target_ulong a0, int v) ! 4718: { ! 4719: int low, high; ! 4720: low = ldl(a0); ! 4721: high = ldl(a0 + 4); ! 4722: if (v < low || v > high) { ! 4723: raise_exception(EXCP05_BOUND); ! 4724: } ! 4725: } ! 4726: ! 4727: static float approx_rsqrt(float a) ! 4728: { ! 4729: return 1.0 / sqrt(a); ! 4730: } ! 4731: ! 4732: static float approx_rcp(float a) ! 4733: { ! 4734: return 1.0 / a; ! 4735: } ! 4736: ! 4737: #if !defined(CONFIG_USER_ONLY) ! 4738: ! 4739: #define MMUSUFFIX _mmu ! 4740: ! 4741: #define SHIFT 0 ! 4742: #include "softmmu_template.h" ! 4743: ! 4744: #define SHIFT 1 ! 4745: #include "softmmu_template.h" ! 4746: ! 4747: #define SHIFT 2 ! 4748: #include "softmmu_template.h" ! 4749: ! 4750: #define SHIFT 3 ! 4751: #include "softmmu_template.h" ! 4752: ! 4753: #endif ! 4754: ! 4755: #if !defined(CONFIG_USER_ONLY) ! 4756: /* try to fill the TLB and return an exception if error. If retaddr is ! 4757: NULL, it means that the function was called in C code (i.e. not ! 4758: from generated code or from helper.c) */ ! 4759: /* XXX: fix it to restore all registers */ ! 4760: void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr) ! 4761: { ! 4762: TranslationBlock *tb; ! 4763: int ret; ! 4764: unsigned long pc; ! 4765: CPUX86State *saved_env; ! 4766: ! 4767: /* XXX: hack to restore env in all cases, even if not called from ! 4768: generated code */ ! 4769: saved_env = env; ! 4770: env = cpu_single_env; ! 4771: ! 4772: ret = cpu_x86_handle_mmu_fault(env, addr, is_write, mmu_idx, 1); ! 4773: if (ret) { ! 4774: if (retaddr) { ! 4775: /* now we have a real cpu fault */ ! 4776: pc = (unsigned long)retaddr; ! 4777: tb = tb_find_pc(pc); ! 4778: if (tb) { ! 4779: /* the PC is inside the translated code. It means that we have ! 4780: a virtual CPU fault */ ! 4781: cpu_restore_state(tb, env, pc, NULL); ! 4782: } ! 4783: } ! 4784: raise_exception_err(env->exception_index, env->error_code); ! 4785: } ! 4786: env = saved_env; ! 4787: } ! 4788: #endif ! 4789: ! 4790: /* Secure Virtual Machine helpers */ ! 4791: ! 4792: #if defined(CONFIG_USER_ONLY) ! 4793: ! 4794: void helper_vmrun(int aflag, int next_eip_addend) ! 4795: { ! 4796: } ! 4797: void helper_vmmcall(void) ! 4798: { ! 4799: } ! 4800: void helper_vmload(int aflag) ! 4801: { ! 4802: } ! 4803: void helper_vmsave(int aflag) ! 4804: { ! 4805: } ! 4806: void helper_stgi(void) ! 4807: { ! 4808: } ! 4809: void helper_clgi(void) ! 4810: { ! 4811: } ! 4812: void helper_skinit(void) ! 4813: { ! 4814: } ! 4815: void helper_invlpga(int aflag) ! 4816: { ! 4817: } ! 4818: void helper_vmexit(uint32_t exit_code, uint64_t exit_info_1) ! 4819: { ! 4820: } ! 4821: void helper_svm_check_intercept_param(uint32_t type, uint64_t param) ! 4822: { ! 4823: } ! 4824: ! 4825: void helper_svm_check_io(uint32_t port, uint32_t param, ! 4826: uint32_t next_eip_addend) ! 4827: { ! 4828: } ! 4829: #else ! 4830: ! 4831: static inline void svm_save_seg(target_phys_addr_t addr, ! 4832: const SegmentCache *sc) ! 4833: { ! 4834: stw_phys(addr + offsetof(struct vmcb_seg, selector), ! 4835: sc->selector); ! 4836: stq_phys(addr + offsetof(struct vmcb_seg, base), ! 4837: sc->base); ! 4838: stl_phys(addr + offsetof(struct vmcb_seg, limit), ! 4839: sc->limit); ! 4840: stw_phys(addr + offsetof(struct vmcb_seg, attrib), ! 4841: ((sc->flags >> 8) & 0xff) | ((sc->flags >> 12) & 0x0f00)); ! 4842: } ! 4843: ! 4844: static inline void svm_load_seg(target_phys_addr_t addr, SegmentCache *sc) ! 4845: { ! 4846: unsigned int flags; ! 4847: ! 4848: sc->selector = lduw_phys(addr + offsetof(struct vmcb_seg, selector)); ! 4849: sc->base = ldq_phys(addr + offsetof(struct vmcb_seg, base)); ! 4850: sc->limit = ldl_phys(addr + offsetof(struct vmcb_seg, limit)); ! 4851: flags = lduw_phys(addr + offsetof(struct vmcb_seg, attrib)); ! 4852: sc->flags = ((flags & 0xff) << 8) | ((flags & 0x0f00) << 12); ! 4853: } ! 4854: ! 4855: static inline void svm_load_seg_cache(target_phys_addr_t addr, ! 4856: CPUState *env, int seg_reg) ! 4857: { ! 4858: SegmentCache sc1, *sc = &sc1; ! 4859: svm_load_seg(addr, sc); ! 4860: cpu_x86_load_seg_cache(env, seg_reg, sc->selector, ! 4861: sc->base, sc->limit, sc->flags); ! 4862: } ! 4863: ! 4864: void helper_vmrun(int aflag, int next_eip_addend) ! 4865: { ! 4866: target_ulong addr; ! 4867: uint32_t event_inj; ! 4868: uint32_t int_ctl; ! 4869: ! 4870: helper_svm_check_intercept_param(SVM_EXIT_VMRUN, 0); ! 4871: ! 4872: if (aflag == 2) ! 4873: addr = EAX; ! 4874: else ! 4875: addr = (uint32_t)EAX; ! 4876: ! 4877: qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmrun! " TARGET_FMT_lx "\n", addr); ! 4878: ! 4879: env->vm_vmcb = addr; ! 4880: ! 4881: /* save the current CPU state in the hsave page */ ! 4882: stq_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.base), env->gdt.base); ! 4883: stl_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.limit), env->gdt.limit); ! 4884: ! 4885: stq_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.base), env->idt.base); ! 4886: stl_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.limit), env->idt.limit); ! 4887: ! 4888: stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr0), env->cr[0]); ! 4889: stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr2), env->cr[2]); ! 4890: stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr3), env->cr[3]); ! 4891: stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr4), env->cr[4]); ! 4892: stq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr6), env->dr[6]); ! 4893: stq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr7), env->dr[7]); ! 4894: ! 4895: stq_phys(env->vm_hsave + offsetof(struct vmcb, save.efer), env->efer); ! 4896: stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rflags), compute_eflags()); ! 4897: ! 4898: svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.es), ! 4899: &env->segs[R_ES]); ! 4900: svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.cs), ! 4901: &env->segs[R_CS]); ! 4902: svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.ss), ! 4903: &env->segs[R_SS]); ! 4904: svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.ds), ! 4905: &env->segs[R_DS]); ! 4906: ! 4907: stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rip), ! 4908: EIP + next_eip_addend); ! 4909: stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rsp), ESP); ! 4910: stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rax), EAX); ! 4911: ! 4912: /* load the interception bitmaps so we do not need to access the ! 4913: vmcb in svm mode */ ! 4914: env->intercept = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept)); ! 4915: env->intercept_cr_read = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_cr_read)); ! 4916: env->intercept_cr_write = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_cr_write)); ! 4917: env->intercept_dr_read = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_dr_read)); ! 4918: env->intercept_dr_write = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_dr_write)); ! 4919: env->intercept_exceptions = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_exceptions)); ! 4920: ! 4921: /* enable intercepts */ ! 4922: env->hflags |= HF_SVMI_MASK; ! 4923: ! 4924: env->tsc_offset = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.tsc_offset)); ! 4925: ! 4926: env->gdt.base = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.base)); ! 4927: env->gdt.limit = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.limit)); ! 4928: ! 4929: env->idt.base = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.base)); ! 4930: env->idt.limit = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.limit)); ! 4931: ! 4932: /* clear exit_info_2 so we behave like the real hardware */ ! 4933: stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), 0); ! 4934: ! 4935: cpu_x86_update_cr0(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr0))); ! 4936: cpu_x86_update_cr4(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr4))); ! 4937: cpu_x86_update_cr3(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr3))); ! 4938: env->cr[2] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr2)); ! 4939: int_ctl = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl)); ! 4940: env->hflags2 &= ~(HF2_HIF_MASK | HF2_VINTR_MASK); ! 4941: if (int_ctl & V_INTR_MASKING_MASK) { ! 4942: env->v_tpr = int_ctl & V_TPR_MASK; ! 4943: env->hflags2 |= HF2_VINTR_MASK; ! 4944: if (env->eflags & IF_MASK) ! 4945: env->hflags2 |= HF2_HIF_MASK; ! 4946: } ! 4947: ! 4948: cpu_load_efer(env, ! 4949: ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.efer))); ! 4950: env->eflags = 0; ! 4951: load_eflags(ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rflags)), ! 4952: ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK)); ! 4953: CC_OP = CC_OP_EFLAGS; ! 4954: ! 4955: svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.es), ! 4956: env, R_ES); ! 4957: svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.cs), ! 4958: env, R_CS); ! 4959: svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.ss), ! 4960: env, R_SS); ! 4961: svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.ds), ! 4962: env, R_DS); ! 4963: ! 4964: EIP = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rip)); ! 4965: env->eip = EIP; ! 4966: ESP = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rsp)); ! 4967: EAX = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rax)); ! 4968: env->dr[7] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr7)); ! 4969: env->dr[6] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr6)); ! 4970: cpu_x86_set_cpl(env, ldub_phys(env->vm_vmcb + offsetof(struct vmcb, save.cpl))); ! 4971: ! 4972: /* FIXME: guest state consistency checks */ ! 4973: ! 4974: switch(ldub_phys(env->vm_vmcb + offsetof(struct vmcb, control.tlb_ctl))) { ! 4975: case TLB_CONTROL_DO_NOTHING: ! 4976: break; ! 4977: case TLB_CONTROL_FLUSH_ALL_ASID: ! 4978: /* FIXME: this is not 100% correct but should work for now */ ! 4979: tlb_flush(env, 1); ! 4980: break; ! 4981: } ! 4982: ! 4983: env->hflags2 |= HF2_GIF_MASK; ! 4984: ! 4985: if (int_ctl & V_IRQ_MASK) { ! 4986: env->interrupt_request |= CPU_INTERRUPT_VIRQ; ! 4987: } ! 4988: ! 4989: /* maybe we need to inject an event */ ! 4990: event_inj = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj)); ! 4991: if (event_inj & SVM_EVTINJ_VALID) { ! 4992: uint8_t vector = event_inj & SVM_EVTINJ_VEC_MASK; ! 4993: uint16_t valid_err = event_inj & SVM_EVTINJ_VALID_ERR; ! 4994: uint32_t event_inj_err = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj_err)); ! 4995: stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj), event_inj & ~SVM_EVTINJ_VALID); ! 4996: ! 4997: qemu_log_mask(CPU_LOG_TB_IN_ASM, "Injecting(%#hx): ", valid_err); ! 4998: /* FIXME: need to implement valid_err */ ! 4999: switch (event_inj & SVM_EVTINJ_TYPE_MASK) { ! 5000: case SVM_EVTINJ_TYPE_INTR: ! 5001: env->exception_index = vector; ! 5002: env->error_code = event_inj_err; ! 5003: env->exception_is_int = 0; ! 5004: env->exception_next_eip = -1; ! 5005: qemu_log_mask(CPU_LOG_TB_IN_ASM, "INTR"); ! 5006: /* XXX: is it always correct ? */ ! 5007: do_interrupt(vector, 0, 0, 0, 1); ! 5008: break; ! 5009: case SVM_EVTINJ_TYPE_NMI: ! 5010: env->exception_index = EXCP02_NMI; ! 5011: env->error_code = event_inj_err; ! 5012: env->exception_is_int = 0; ! 5013: env->exception_next_eip = EIP; ! 5014: qemu_log_mask(CPU_LOG_TB_IN_ASM, "NMI"); ! 5015: cpu_loop_exit(); ! 5016: break; ! 5017: case SVM_EVTINJ_TYPE_EXEPT: ! 5018: env->exception_index = vector; ! 5019: env->error_code = event_inj_err; ! 5020: env->exception_is_int = 0; ! 5021: env->exception_next_eip = -1; ! 5022: qemu_log_mask(CPU_LOG_TB_IN_ASM, "EXEPT"); ! 5023: cpu_loop_exit(); ! 5024: break; ! 5025: case SVM_EVTINJ_TYPE_SOFT: ! 5026: env->exception_index = vector; ! 5027: env->error_code = event_inj_err; ! 5028: env->exception_is_int = 1; ! 5029: env->exception_next_eip = EIP; ! 5030: qemu_log_mask(CPU_LOG_TB_IN_ASM, "SOFT"); ! 5031: cpu_loop_exit(); ! 5032: break; ! 5033: } ! 5034: qemu_log_mask(CPU_LOG_TB_IN_ASM, " %#x %#x\n", env->exception_index, env->error_code); ! 5035: } ! 5036: } ! 5037: ! 5038: void helper_vmmcall(void) ! 5039: { ! 5040: helper_svm_check_intercept_param(SVM_EXIT_VMMCALL, 0); ! 5041: raise_exception(EXCP06_ILLOP); ! 5042: } ! 5043: ! 5044: void helper_vmload(int aflag) ! 5045: { ! 5046: target_ulong addr; ! 5047: helper_svm_check_intercept_param(SVM_EXIT_VMLOAD, 0); ! 5048: ! 5049: if (aflag == 2) ! 5050: addr = EAX; ! 5051: else ! 5052: addr = (uint32_t)EAX; ! 5053: ! 5054: qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmload! " TARGET_FMT_lx "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n", ! 5055: addr, ldq_phys(addr + offsetof(struct vmcb, save.fs.base)), ! 5056: env->segs[R_FS].base); ! 5057: ! 5058: svm_load_seg_cache(addr + offsetof(struct vmcb, save.fs), ! 5059: env, R_FS); ! 5060: svm_load_seg_cache(addr + offsetof(struct vmcb, save.gs), ! 5061: env, R_GS); ! 5062: svm_load_seg(addr + offsetof(struct vmcb, save.tr), ! 5063: &env->tr); ! 5064: svm_load_seg(addr + offsetof(struct vmcb, save.ldtr), ! 5065: &env->ldt); ! 5066: ! 5067: #ifdef TARGET_X86_64 ! 5068: env->kernelgsbase = ldq_phys(addr + offsetof(struct vmcb, save.kernel_gs_base)); ! 5069: env->lstar = ldq_phys(addr + offsetof(struct vmcb, save.lstar)); ! 5070: env->cstar = ldq_phys(addr + offsetof(struct vmcb, save.cstar)); ! 5071: env->fmask = ldq_phys(addr + offsetof(struct vmcb, save.sfmask)); ! 5072: #endif ! 5073: env->star = ldq_phys(addr + offsetof(struct vmcb, save.star)); ! 5074: env->sysenter_cs = ldq_phys(addr + offsetof(struct vmcb, save.sysenter_cs)); ! 5075: env->sysenter_esp = ldq_phys(addr + offsetof(struct vmcb, save.sysenter_esp)); ! 5076: env->sysenter_eip = ldq_phys(addr + offsetof(struct vmcb, save.sysenter_eip)); ! 5077: } ! 5078: ! 5079: void helper_vmsave(int aflag) ! 5080: { ! 5081: target_ulong addr; ! 5082: helper_svm_check_intercept_param(SVM_EXIT_VMSAVE, 0); ! 5083: ! 5084: if (aflag == 2) ! 5085: addr = EAX; ! 5086: else ! 5087: addr = (uint32_t)EAX; ! 5088: ! 5089: qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmsave! " TARGET_FMT_lx "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n", ! 5090: addr, ldq_phys(addr + offsetof(struct vmcb, save.fs.base)), ! 5091: env->segs[R_FS].base); ! 5092: ! 5093: svm_save_seg(addr + offsetof(struct vmcb, save.fs), ! 5094: &env->segs[R_FS]); ! 5095: svm_save_seg(addr + offsetof(struct vmcb, save.gs), ! 5096: &env->segs[R_GS]); ! 5097: svm_save_seg(addr + offsetof(struct vmcb, save.tr), ! 5098: &env->tr); ! 5099: svm_save_seg(addr + offsetof(struct vmcb, save.ldtr), ! 5100: &env->ldt); ! 5101: ! 5102: #ifdef TARGET_X86_64 ! 5103: stq_phys(addr + offsetof(struct vmcb, save.kernel_gs_base), env->kernelgsbase); ! 5104: stq_phys(addr + offsetof(struct vmcb, save.lstar), env->lstar); ! 5105: stq_phys(addr + offsetof(struct vmcb, save.cstar), env->cstar); ! 5106: stq_phys(addr + offsetof(struct vmcb, save.sfmask), env->fmask); ! 5107: #endif ! 5108: stq_phys(addr + offsetof(struct vmcb, save.star), env->star); ! 5109: stq_phys(addr + offsetof(struct vmcb, save.sysenter_cs), env->sysenter_cs); ! 5110: stq_phys(addr + offsetof(struct vmcb, save.sysenter_esp), env->sysenter_esp); ! 5111: stq_phys(addr + offsetof(struct vmcb, save.sysenter_eip), env->sysenter_eip); ! 5112: } ! 5113: ! 5114: void helper_stgi(void) ! 5115: { ! 5116: helper_svm_check_intercept_param(SVM_EXIT_STGI, 0); ! 5117: env->hflags2 |= HF2_GIF_MASK; ! 5118: } ! 5119: ! 5120: void helper_clgi(void) ! 5121: { ! 5122: helper_svm_check_intercept_param(SVM_EXIT_CLGI, 0); ! 5123: env->hflags2 &= ~HF2_GIF_MASK; ! 5124: } ! 5125: ! 5126: void helper_skinit(void) ! 5127: { ! 5128: helper_svm_check_intercept_param(SVM_EXIT_SKINIT, 0); ! 5129: /* XXX: not implemented */ ! 5130: raise_exception(EXCP06_ILLOP); ! 5131: } ! 5132: ! 5133: void helper_invlpga(int aflag) ! 5134: { ! 5135: target_ulong addr; ! 5136: helper_svm_check_intercept_param(SVM_EXIT_INVLPGA, 0); ! 5137: ! 5138: if (aflag == 2) ! 5139: addr = EAX; ! 5140: else ! 5141: addr = (uint32_t)EAX; ! 5142: ! 5143: /* XXX: could use the ASID to see if it is needed to do the ! 5144: flush */ ! 5145: tlb_flush_page(env, addr); ! 5146: } ! 5147: ! 5148: void helper_svm_check_intercept_param(uint32_t type, uint64_t param) ! 5149: { ! 5150: if (likely(!(env->hflags & HF_SVMI_MASK))) ! 5151: return; ! 5152: switch(type) { ! 5153: case SVM_EXIT_READ_CR0 ... SVM_EXIT_READ_CR0 + 8: ! 5154: if (env->intercept_cr_read & (1 << (type - SVM_EXIT_READ_CR0))) { ! 5155: helper_vmexit(type, param); ! 5156: } ! 5157: break; ! 5158: case SVM_EXIT_WRITE_CR0 ... SVM_EXIT_WRITE_CR0 + 8: ! 5159: if (env->intercept_cr_write & (1 << (type - SVM_EXIT_WRITE_CR0))) { ! 5160: helper_vmexit(type, param); ! 5161: } ! 5162: break; ! 5163: case SVM_EXIT_READ_DR0 ... SVM_EXIT_READ_DR0 + 7: ! 5164: if (env->intercept_dr_read & (1 << (type - SVM_EXIT_READ_DR0))) { ! 5165: helper_vmexit(type, param); ! 5166: } ! 5167: break; ! 5168: case SVM_EXIT_WRITE_DR0 ... SVM_EXIT_WRITE_DR0 + 7: ! 5169: if (env->intercept_dr_write & (1 << (type - SVM_EXIT_WRITE_DR0))) { ! 5170: helper_vmexit(type, param); ! 5171: } ! 5172: break; ! 5173: case SVM_EXIT_EXCP_BASE ... SVM_EXIT_EXCP_BASE + 31: ! 5174: if (env->intercept_exceptions & (1 << (type - SVM_EXIT_EXCP_BASE))) { ! 5175: helper_vmexit(type, param); ! 5176: } ! 5177: break; ! 5178: case SVM_EXIT_MSR: ! 5179: if (env->intercept & (1ULL << (SVM_EXIT_MSR - SVM_EXIT_INTR))) { ! 5180: /* FIXME: this should be read in at vmrun (faster this way?) */ ! 5181: uint64_t addr = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.msrpm_base_pa)); ! 5182: uint32_t t0, t1; ! 5183: switch((uint32_t)ECX) { ! 5184: case 0 ... 0x1fff: ! 5185: t0 = (ECX * 2) % 8; ! 5186: t1 = ECX / 8; ! 5187: break; ! 5188: case 0xc0000000 ... 0xc0001fff: ! 5189: t0 = (8192 + ECX - 0xc0000000) * 2; ! 5190: t1 = (t0 / 8); ! 5191: t0 %= 8; ! 5192: break; ! 5193: case 0xc0010000 ... 0xc0011fff: ! 5194: t0 = (16384 + ECX - 0xc0010000) * 2; ! 5195: t1 = (t0 / 8); ! 5196: t0 %= 8; ! 5197: break; ! 5198: default: ! 5199: helper_vmexit(type, param); ! 5200: t0 = 0; ! 5201: t1 = 0; ! 5202: break; ! 5203: } ! 5204: if (ldub_phys(addr + t1) & ((1 << param) << t0)) ! 5205: helper_vmexit(type, param); ! 5206: } ! 5207: break; ! 5208: default: ! 5209: if (env->intercept & (1ULL << (type - SVM_EXIT_INTR))) { ! 5210: helper_vmexit(type, param); ! 5211: } ! 5212: break; ! 5213: } ! 5214: } ! 5215: ! 5216: void helper_svm_check_io(uint32_t port, uint32_t param, ! 5217: uint32_t next_eip_addend) ! 5218: { ! 5219: if (env->intercept & (1ULL << (SVM_EXIT_IOIO - SVM_EXIT_INTR))) { ! 5220: /* FIXME: this should be read in at vmrun (faster this way?) */ ! 5221: uint64_t addr = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.iopm_base_pa)); ! 5222: uint16_t mask = (1 << ((param >> 4) & 7)) - 1; ! 5223: if(lduw_phys(addr + port / 8) & (mask << (port & 7))) { ! 5224: /* next EIP */ ! 5225: stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), ! 5226: env->eip + next_eip_addend); ! 5227: helper_vmexit(SVM_EXIT_IOIO, param | (port << 16)); ! 5228: } ! 5229: } ! 5230: } ! 5231: ! 5232: /* Note: currently only 32 bits of exit_code are used */ ! 5233: void helper_vmexit(uint32_t exit_code, uint64_t exit_info_1) ! 5234: { ! 5235: uint32_t int_ctl; ! 5236: ! 5237: qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmexit(%08x, %016" PRIx64 ", %016" PRIx64 ", " TARGET_FMT_lx ")!\n", ! 5238: exit_code, exit_info_1, ! 5239: ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2)), ! 5240: EIP); ! 5241: ! 5242: if(env->hflags & HF_INHIBIT_IRQ_MASK) { ! 5243: stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_state), SVM_INTERRUPT_SHADOW_MASK); ! 5244: env->hflags &= ~HF_INHIBIT_IRQ_MASK; ! 5245: } else { ! 5246: stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_state), 0); ! 5247: } ! 5248: ! 5249: /* Save the VM state in the vmcb */ ! 5250: svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.es), ! 5251: &env->segs[R_ES]); ! 5252: svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.cs), ! 5253: &env->segs[R_CS]); ! 5254: svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.ss), ! 5255: &env->segs[R_SS]); ! 5256: svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.ds), ! 5257: &env->segs[R_DS]); ! 5258: ! 5259: stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.base), env->gdt.base); ! 5260: stl_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.limit), env->gdt.limit); ! 5261: ! 5262: stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.base), env->idt.base); ! 5263: stl_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.limit), env->idt.limit); ! 5264: ! 5265: stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.efer), env->efer); ! 5266: stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr0), env->cr[0]); ! 5267: stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr2), env->cr[2]); ! 5268: stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr3), env->cr[3]); ! 5269: stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr4), env->cr[4]); ! 5270: ! 5271: int_ctl = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl)); ! 5272: int_ctl &= ~(V_TPR_MASK | V_IRQ_MASK); ! 5273: int_ctl |= env->v_tpr & V_TPR_MASK; ! 5274: if (env->interrupt_request & CPU_INTERRUPT_VIRQ) ! 5275: int_ctl |= V_IRQ_MASK; ! 5276: stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl), int_ctl); ! 5277: ! 5278: stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rflags), compute_eflags()); ! 5279: stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rip), env->eip); ! 5280: stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rsp), ESP); ! 5281: stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rax), EAX); ! 5282: stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr7), env->dr[7]); ! 5283: stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr6), env->dr[6]); ! 5284: stb_phys(env->vm_vmcb + offsetof(struct vmcb, save.cpl), env->hflags & HF_CPL_MASK); ! 5285: ! 5286: /* Reload the host state from vm_hsave */ ! 5287: env->hflags2 &= ~(HF2_HIF_MASK | HF2_VINTR_MASK); ! 5288: env->hflags &= ~HF_SVMI_MASK; ! 5289: env->intercept = 0; ! 5290: env->intercept_exceptions = 0; ! 5291: env->interrupt_request &= ~CPU_INTERRUPT_VIRQ; ! 5292: env->tsc_offset = 0; ! 5293: ! 5294: env->gdt.base = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.base)); ! 5295: env->gdt.limit = ldl_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.limit)); ! 5296: ! 5297: env->idt.base = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.base)); ! 5298: env->idt.limit = ldl_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.limit)); ! 5299: ! 5300: cpu_x86_update_cr0(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr0)) | CR0_PE_MASK); ! 5301: cpu_x86_update_cr4(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr4))); ! 5302: cpu_x86_update_cr3(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr3))); ! 5303: /* we need to set the efer after the crs so the hidden flags get ! 5304: set properly */ ! 5305: cpu_load_efer(env, ! 5306: ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.efer))); ! 5307: env->eflags = 0; ! 5308: load_eflags(ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rflags)), ! 5309: ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK)); ! 5310: CC_OP = CC_OP_EFLAGS; ! 5311: ! 5312: svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.es), ! 5313: env, R_ES); ! 5314: svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.cs), ! 5315: env, R_CS); ! 5316: svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.ss), ! 5317: env, R_SS); ! 5318: svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.ds), ! 5319: env, R_DS); ! 5320: ! 5321: EIP = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rip)); ! 5322: ESP = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rsp)); ! 5323: EAX = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rax)); ! 5324: ! 5325: env->dr[6] = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr6)); ! 5326: env->dr[7] = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr7)); ! 5327: ! 5328: /* other setups */ ! 5329: cpu_x86_set_cpl(env, 0); ! 5330: stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_code), exit_code); ! 5331: stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_1), exit_info_1); ! 5332: ! 5333: env->hflags2 &= ~HF2_GIF_MASK; ! 5334: /* FIXME: Resets the current ASID register to zero (host ASID). */ ! 5335: ! 5336: /* Clears the V_IRQ and V_INTR_MASKING bits inside the processor. */ ! 5337: ! 5338: /* Clears the TSC_OFFSET inside the processor. */ ! 5339: ! 5340: /* If the host is in PAE mode, the processor reloads the host's PDPEs ! 5341: from the page table indicated the host's CR3. If the PDPEs contain ! 5342: illegal state, the processor causes a shutdown. */ ! 5343: ! 5344: /* Forces CR0.PE = 1, RFLAGS.VM = 0. */ ! 5345: env->cr[0] |= CR0_PE_MASK; ! 5346: env->eflags &= ~VM_MASK; ! 5347: ! 5348: /* Disables all breakpoints in the host DR7 register. */ ! 5349: ! 5350: /* Checks the reloaded host state for consistency. */ ! 5351: ! 5352: /* If the host's rIP reloaded by #VMEXIT is outside the limit of the ! 5353: host's code segment or non-canonical (in the case of long mode), a ! 5354: #GP fault is delivered inside the host.) */ ! 5355: ! 5356: /* remove any pending exception */ ! 5357: env->exception_index = -1; ! 5358: env->error_code = 0; ! 5359: env->old_exception = -1; ! 5360: ! 5361: cpu_loop_exit(); ! 5362: } ! 5363: ! 5364: #endif ! 5365: ! 5366: /* MMX/SSE */ ! 5367: /* XXX: optimize by storing fptt and fptags in the static cpu state */ ! 5368: void helper_enter_mmx(void) ! 5369: { ! 5370: env->fpstt = 0; ! 5371: *(uint32_t *)(env->fptags) = 0; ! 5372: *(uint32_t *)(env->fptags + 4) = 0; ! 5373: } ! 5374: ! 5375: void helper_emms(void) ! 5376: { ! 5377: /* set to empty state */ ! 5378: *(uint32_t *)(env->fptags) = 0x01010101; ! 5379: *(uint32_t *)(env->fptags + 4) = 0x01010101; ! 5380: } ! 5381: ! 5382: /* XXX: suppress */ ! 5383: void helper_movq(void *d, void *s) ! 5384: { ! 5385: *(uint64_t *)d = *(uint64_t *)s; ! 5386: } ! 5387: ! 5388: #define SHIFT 0 ! 5389: #include "ops_sse.h" ! 5390: ! 5391: #define SHIFT 1 ! 5392: #include "ops_sse.h" ! 5393: ! 5394: #define SHIFT 0 ! 5395: #include "helper_template.h" ! 5396: #undef SHIFT ! 5397: ! 5398: #define SHIFT 1 ! 5399: #include "helper_template.h" ! 5400: #undef SHIFT ! 5401: ! 5402: #define SHIFT 2 ! 5403: #include "helper_template.h" ! 5404: #undef SHIFT ! 5405: ! 5406: #ifdef TARGET_X86_64 ! 5407: ! 5408: #define SHIFT 3 ! 5409: #include "helper_template.h" ! 5410: #undef SHIFT ! 5411: ! 5412: #endif ! 5413: ! 5414: /* bit operations */ ! 5415: target_ulong helper_bsf(target_ulong t0) ! 5416: { ! 5417: int count; ! 5418: target_ulong res; ! 5419: ! 5420: res = t0; ! 5421: count = 0; ! 5422: while ((res & 1) == 0) { ! 5423: count++; ! 5424: res >>= 1; ! 5425: } ! 5426: return count; ! 5427: } ! 5428: ! 5429: target_ulong helper_bsr(target_ulong t0) ! 5430: { ! 5431: int count; ! 5432: target_ulong res, mask; ! 5433: ! 5434: res = t0; ! 5435: count = TARGET_LONG_BITS - 1; ! 5436: mask = (target_ulong)1 << (TARGET_LONG_BITS - 1); ! 5437: while ((res & mask) == 0) { ! 5438: count--; ! 5439: res <<= 1; ! 5440: } ! 5441: return count; ! 5442: } ! 5443: ! 5444: ! 5445: static int compute_all_eflags(void) ! 5446: { ! 5447: return CC_SRC; ! 5448: } ! 5449: ! 5450: static int compute_c_eflags(void) ! 5451: { ! 5452: return CC_SRC & CC_C; ! 5453: } ! 5454: ! 5455: uint32_t helper_cc_compute_all(int op) ! 5456: { ! 5457: switch (op) { ! 5458: default: /* should never happen */ return 0; ! 5459: ! 5460: case CC_OP_EFLAGS: return compute_all_eflags(); ! 5461: ! 5462: case CC_OP_MULB: return compute_all_mulb(); ! 5463: case CC_OP_MULW: return compute_all_mulw(); ! 5464: case CC_OP_MULL: return compute_all_mull(); ! 5465: ! 5466: case CC_OP_ADDB: return compute_all_addb(); ! 5467: case CC_OP_ADDW: return compute_all_addw(); ! 5468: case CC_OP_ADDL: return compute_all_addl(); ! 5469: ! 5470: case CC_OP_ADCB: return compute_all_adcb(); ! 5471: case CC_OP_ADCW: return compute_all_adcw(); ! 5472: case CC_OP_ADCL: return compute_all_adcl(); ! 5473: ! 5474: case CC_OP_SUBB: return compute_all_subb(); ! 5475: case CC_OP_SUBW: return compute_all_subw(); ! 5476: case CC_OP_SUBL: return compute_all_subl(); ! 5477: ! 5478: case CC_OP_SBBB: return compute_all_sbbb(); ! 5479: case CC_OP_SBBW: return compute_all_sbbw(); ! 5480: case CC_OP_SBBL: return compute_all_sbbl(); ! 5481: ! 5482: case CC_OP_LOGICB: return compute_all_logicb(); ! 5483: case CC_OP_LOGICW: return compute_all_logicw(); ! 5484: case CC_OP_LOGICL: return compute_all_logicl(); ! 5485: ! 5486: case CC_OP_INCB: return compute_all_incb(); ! 5487: case CC_OP_INCW: return compute_all_incw(); ! 5488: case CC_OP_INCL: return compute_all_incl(); ! 5489: ! 5490: case CC_OP_DECB: return compute_all_decb(); ! 5491: case CC_OP_DECW: return compute_all_decw(); ! 5492: case CC_OP_DECL: return compute_all_decl(); ! 5493: ! 5494: case CC_OP_SHLB: return compute_all_shlb(); ! 5495: case CC_OP_SHLW: return compute_all_shlw(); ! 5496: case CC_OP_SHLL: return compute_all_shll(); ! 5497: ! 5498: case CC_OP_SARB: return compute_all_sarb(); ! 5499: case CC_OP_SARW: return compute_all_sarw(); ! 5500: case CC_OP_SARL: return compute_all_sarl(); ! 5501: ! 5502: #ifdef TARGET_X86_64 ! 5503: case CC_OP_MULQ: return compute_all_mulq(); ! 5504: ! 5505: case CC_OP_ADDQ: return compute_all_addq(); ! 5506: ! 5507: case CC_OP_ADCQ: return compute_all_adcq(); ! 5508: ! 5509: case CC_OP_SUBQ: return compute_all_subq(); ! 5510: ! 5511: case CC_OP_SBBQ: return compute_all_sbbq(); ! 5512: ! 5513: case CC_OP_LOGICQ: return compute_all_logicq(); ! 5514: ! 5515: case CC_OP_INCQ: return compute_all_incq(); ! 5516: ! 5517: case CC_OP_DECQ: return compute_all_decq(); ! 5518: ! 5519: case CC_OP_SHLQ: return compute_all_shlq(); ! 5520: ! 5521: case CC_OP_SARQ: return compute_all_sarq(); ! 5522: #endif ! 5523: } ! 5524: } ! 5525: ! 5526: uint32_t helper_cc_compute_c(int op) ! 5527: { ! 5528: switch (op) { ! 5529: default: /* should never happen */ return 0; ! 5530: ! 5531: case CC_OP_EFLAGS: return compute_c_eflags(); ! 5532: ! 5533: case CC_OP_MULB: return compute_c_mull(); ! 5534: case CC_OP_MULW: return compute_c_mull(); ! 5535: case CC_OP_MULL: return compute_c_mull(); ! 5536: ! 5537: case CC_OP_ADDB: return compute_c_addb(); ! 5538: case CC_OP_ADDW: return compute_c_addw(); ! 5539: case CC_OP_ADDL: return compute_c_addl(); ! 5540: ! 5541: case CC_OP_ADCB: return compute_c_adcb(); ! 5542: case CC_OP_ADCW: return compute_c_adcw(); ! 5543: case CC_OP_ADCL: return compute_c_adcl(); ! 5544: ! 5545: case CC_OP_SUBB: return compute_c_subb(); ! 5546: case CC_OP_SUBW: return compute_c_subw(); ! 5547: case CC_OP_SUBL: return compute_c_subl(); ! 5548: ! 5549: case CC_OP_SBBB: return compute_c_sbbb(); ! 5550: case CC_OP_SBBW: return compute_c_sbbw(); ! 5551: case CC_OP_SBBL: return compute_c_sbbl(); ! 5552: ! 5553: case CC_OP_LOGICB: return compute_c_logicb(); ! 5554: case CC_OP_LOGICW: return compute_c_logicw(); ! 5555: case CC_OP_LOGICL: return compute_c_logicl(); ! 5556: ! 5557: case CC_OP_INCB: return compute_c_incl(); ! 5558: case CC_OP_INCW: return compute_c_incl(); ! 5559: case CC_OP_INCL: return compute_c_incl(); ! 5560: ! 5561: case CC_OP_DECB: return compute_c_incl(); ! 5562: case CC_OP_DECW: return compute_c_incl(); ! 5563: case CC_OP_DECL: return compute_c_incl(); ! 5564: ! 5565: case CC_OP_SHLB: return compute_c_shlb(); ! 5566: case CC_OP_SHLW: return compute_c_shlw(); ! 5567: case CC_OP_SHLL: return compute_c_shll(); ! 5568: ! 5569: case CC_OP_SARB: return compute_c_sarl(); ! 5570: case CC_OP_SARW: return compute_c_sarl(); ! 5571: case CC_OP_SARL: return compute_c_sarl(); ! 5572: ! 5573: #ifdef TARGET_X86_64 ! 5574: case CC_OP_MULQ: return compute_c_mull(); ! 5575: ! 5576: case CC_OP_ADDQ: return compute_c_addq(); ! 5577: ! 5578: case CC_OP_ADCQ: return compute_c_adcq(); ! 5579: ! 5580: case CC_OP_SUBQ: return compute_c_subq(); ! 5581: ! 5582: case CC_OP_SBBQ: return compute_c_sbbq(); ! 5583: ! 5584: case CC_OP_LOGICQ: return compute_c_logicq(); ! 5585: ! 5586: case CC_OP_INCQ: return compute_c_incl(); ! 5587: ! 5588: case CC_OP_DECQ: return compute_c_incl(); ! 5589: ! 5590: case CC_OP_SHLQ: return compute_c_shlq(); ! 5591: ! 5592: case CC_OP_SARQ: return compute_c_sarl(); ! 5593: #endif ! 5594: } ! 5595: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.