|
|
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ! 19: */ ! 20: #include "exec.h" ! 21: ! 22: //#define DEBUG_PCALL ! 23: ! 24: #if 0 ! 25: #define raise_exception_err(a, b)\ ! 26: do {\ ! 27: fprintf(logfile, "raise_exception line=%d\n", __LINE__);\ ! 28: (raise_exception_err)(a, b);\ ! 29: } while (0) ! 30: #endif ! 31: ! 32: const uint8_t parity_table[256] = { ! 33: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ! 34: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ! 35: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ! 36: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ! 37: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ! 38: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ! 39: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ! 40: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ! 41: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ! 42: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ! 43: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ! 44: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ! 45: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ! 46: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ! 47: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ! 48: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ! 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: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ! 52: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ! 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: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ! 60: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ! 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: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ! 64: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ! 65: }; ! 66: ! 67: /* modulo 17 table */ ! 68: const uint8_t rclw_table[32] = { ! 69: 0, 1, 2, 3, 4, 5, 6, 7, ! 70: 8, 9,10,11,12,13,14,15, ! 71: 16, 0, 1, 2, 3, 4, 5, 6, ! 72: 7, 8, 9,10,11,12,13,14, ! 73: }; ! 74: ! 75: /* modulo 9 table */ ! 76: const uint8_t rclb_table[32] = { ! 77: 0, 1, 2, 3, 4, 5, 6, 7, ! 78: 8, 0, 1, 2, 3, 4, 5, 6, ! 79: 7, 8, 0, 1, 2, 3, 4, 5, ! 80: 6, 7, 8, 0, 1, 2, 3, 4, ! 81: }; ! 82: ! 83: const CPU86_LDouble f15rk[7] = ! 84: { ! 85: 0.00000000000000000000L, ! 86: 1.00000000000000000000L, ! 87: 3.14159265358979323851L, /*pi*/ ! 88: 0.30102999566398119523L, /*lg2*/ ! 89: 0.69314718055994530943L, /*ln2*/ ! 90: 1.44269504088896340739L, /*l2e*/ ! 91: 3.32192809488736234781L, /*l2t*/ ! 92: }; ! 93: ! 94: /* thread support */ ! 95: ! 96: spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED; ! 97: ! 98: void cpu_lock(void) ! 99: { ! 100: spin_lock(&global_cpu_lock); ! 101: } ! 102: ! 103: void cpu_unlock(void) ! 104: { ! 105: spin_unlock(&global_cpu_lock); ! 106: } ! 107: ! 108: void cpu_loop_exit(void) ! 109: { ! 110: /* NOTE: the register at this point must be saved by hand because ! 111: longjmp restore them */ ! 112: regs_to_env(); ! 113: longjmp(env->jmp_env, 1); ! 114: } ! 115: ! 116: /* return non zero if error */ ! 117: static inline int load_segment(uint32_t *e1_ptr, uint32_t *e2_ptr, ! 118: int selector) ! 119: { ! 120: SegmentCache *dt; ! 121: int index; ! 122: target_ulong ptr; ! 123: ! 124: if (selector & 0x4) ! 125: dt = &env->ldt; ! 126: else ! 127: dt = &env->gdt; ! 128: index = selector & ~7; ! 129: if ((index + 7) > dt->limit) ! 130: return -1; ! 131: ptr = dt->base + index; ! 132: *e1_ptr = ldl_kernel(ptr); ! 133: *e2_ptr = ldl_kernel(ptr + 4); ! 134: return 0; ! 135: } ! 136: ! 137: static inline unsigned int get_seg_limit(uint32_t e1, uint32_t e2) ! 138: { ! 139: unsigned int limit; ! 140: limit = (e1 & 0xffff) | (e2 & 0x000f0000); ! 141: if (e2 & DESC_G_MASK) ! 142: limit = (limit << 12) | 0xfff; ! 143: return limit; ! 144: } ! 145: ! 146: static inline uint32_t get_seg_base(uint32_t e1, uint32_t e2) ! 147: { ! 148: return ((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000)); ! 149: } ! 150: ! 151: static inline void load_seg_cache_raw_dt(SegmentCache *sc, uint32_t e1, uint32_t e2) ! 152: { ! 153: sc->base = get_seg_base(e1, e2); ! 154: sc->limit = get_seg_limit(e1, e2); ! 155: sc->flags = e2; ! 156: } ! 157: ! 158: /* init the segment cache in vm86 mode. */ ! 159: static inline void load_seg_vm(int seg, int selector) ! 160: { ! 161: selector &= 0xffff; ! 162: cpu_x86_load_seg_cache(env, seg, selector, ! 163: (selector << 4), 0xffff, 0); ! 164: } ! 165: ! 166: static inline void get_ss_esp_from_tss(uint32_t *ss_ptr, ! 167: uint32_t *esp_ptr, int dpl) ! 168: { ! 169: int type, index, shift; ! 170: ! 171: #if 0 ! 172: { ! 173: int i; ! 174: printf("TR: base=%p limit=%x\n", env->tr.base, env->tr.limit); ! 175: for(i=0;i<env->tr.limit;i++) { ! 176: printf("%02x ", env->tr.base[i]); ! 177: if ((i & 7) == 7) printf("\n"); ! 178: } ! 179: printf("\n"); ! 180: } ! 181: #endif ! 182: ! 183: if (!(env->tr.flags & DESC_P_MASK)) ! 184: cpu_abort(env, "invalid tss"); ! 185: type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf; ! 186: if ((type & 7) != 1) ! 187: cpu_abort(env, "invalid tss type"); ! 188: shift = type >> 3; ! 189: index = (dpl * 4 + 2) << shift; ! 190: if (index + (4 << shift) - 1 > env->tr.limit) ! 191: raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc); ! 192: if (shift == 0) { ! 193: *esp_ptr = lduw_kernel(env->tr.base + index); ! 194: *ss_ptr = lduw_kernel(env->tr.base + index + 2); ! 195: } else { ! 196: *esp_ptr = ldl_kernel(env->tr.base + index); ! 197: *ss_ptr = lduw_kernel(env->tr.base + index + 4); ! 198: } ! 199: } ! 200: ! 201: /* XXX: merge with load_seg() */ ! 202: static void tss_load_seg(int seg_reg, int selector) ! 203: { ! 204: uint32_t e1, e2; ! 205: int rpl, dpl, cpl; ! 206: ! 207: if ((selector & 0xfffc) != 0) { ! 208: if (load_segment(&e1, &e2, selector) != 0) ! 209: raise_exception_err(EXCP0A_TSS, selector & 0xfffc); ! 210: if (!(e2 & DESC_S_MASK)) ! 211: raise_exception_err(EXCP0A_TSS, selector & 0xfffc); ! 212: rpl = selector & 3; ! 213: dpl = (e2 >> DESC_DPL_SHIFT) & 3; ! 214: cpl = env->hflags & HF_CPL_MASK; ! 215: if (seg_reg == R_CS) { ! 216: if (!(e2 & DESC_CS_MASK)) ! 217: raise_exception_err(EXCP0A_TSS, selector & 0xfffc); ! 218: if (dpl != rpl) ! 219: raise_exception_err(EXCP0A_TSS, selector & 0xfffc); ! 220: if ((e2 & DESC_C_MASK) && dpl > rpl) ! 221: raise_exception_err(EXCP0A_TSS, selector & 0xfffc); ! 222: ! 223: } else if (seg_reg == R_SS) { ! 224: /* SS must be writable data */ ! 225: if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK)) ! 226: raise_exception_err(EXCP0A_TSS, selector & 0xfffc); ! 227: if (dpl != cpl || dpl != rpl) ! 228: raise_exception_err(EXCP0A_TSS, selector & 0xfffc); ! 229: } else { ! 230: /* not readable code */ ! 231: if ((e2 & DESC_CS_MASK) && !(e2 & DESC_R_MASK)) ! 232: raise_exception_err(EXCP0A_TSS, selector & 0xfffc); ! 233: /* if data or non conforming code, checks the rights */ ! 234: if (((e2 >> DESC_TYPE_SHIFT) & 0xf) < 12) { ! 235: if (dpl < cpl || dpl < rpl) ! 236: raise_exception_err(EXCP0A_TSS, selector & 0xfffc); ! 237: } ! 238: } ! 239: if (!(e2 & DESC_P_MASK)) ! 240: raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); ! 241: cpu_x86_load_seg_cache(env, seg_reg, selector, ! 242: get_seg_base(e1, e2), ! 243: get_seg_limit(e1, e2), ! 244: e2); ! 245: } else { ! 246: if (seg_reg == R_SS || seg_reg == R_CS) ! 247: raise_exception_err(EXCP0A_TSS, selector & 0xfffc); ! 248: } ! 249: } ! 250: ! 251: #define SWITCH_TSS_JMP 0 ! 252: #define SWITCH_TSS_IRET 1 ! 253: #define SWITCH_TSS_CALL 2 ! 254: ! 255: /* XXX: restore CPU state in registers (PowerPC case) */ ! 256: static void switch_tss(int tss_selector, ! 257: uint32_t e1, uint32_t e2, int source, ! 258: uint32_t next_eip) ! 259: { ! 260: int tss_limit, tss_limit_max, type, old_tss_limit_max, old_type, v1, v2, i; ! 261: target_ulong tss_base; ! 262: uint32_t new_regs[8], new_segs[6]; ! 263: uint32_t new_eflags, new_eip, new_cr3, new_ldt, new_trap; ! 264: uint32_t old_eflags, eflags_mask; ! 265: SegmentCache *dt; ! 266: int index; ! 267: target_ulong ptr; ! 268: ! 269: type = (e2 >> DESC_TYPE_SHIFT) & 0xf; ! 270: #ifdef DEBUG_PCALL ! 271: if (loglevel & CPU_LOG_PCALL) ! 272: fprintf(logfile, "switch_tss: sel=0x%04x type=%d src=%d\n", tss_selector, type, source); ! 273: #endif ! 274: ! 275: /* if task gate, we read the TSS segment and we load it */ ! 276: if (type == 5) { ! 277: if (!(e2 & DESC_P_MASK)) ! 278: raise_exception_err(EXCP0B_NOSEG, tss_selector & 0xfffc); ! 279: tss_selector = e1 >> 16; ! 280: if (tss_selector & 4) ! 281: raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc); ! 282: if (load_segment(&e1, &e2, tss_selector) != 0) ! 283: raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc); ! 284: if (e2 & DESC_S_MASK) ! 285: raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc); ! 286: type = (e2 >> DESC_TYPE_SHIFT) & 0xf; ! 287: if ((type & 7) != 1) ! 288: raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc); ! 289: } ! 290: ! 291: if (!(e2 & DESC_P_MASK)) ! 292: raise_exception_err(EXCP0B_NOSEG, tss_selector & 0xfffc); ! 293: ! 294: if (type & 8) ! 295: tss_limit_max = 103; ! 296: else ! 297: tss_limit_max = 43; ! 298: tss_limit = get_seg_limit(e1, e2); ! 299: tss_base = get_seg_base(e1, e2); ! 300: if ((tss_selector & 4) != 0 || ! 301: tss_limit < tss_limit_max) ! 302: raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc); ! 303: old_type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf; ! 304: if (old_type & 8) ! 305: old_tss_limit_max = 103; ! 306: else ! 307: old_tss_limit_max = 43; ! 308: ! 309: /* read all the registers from the new TSS */ ! 310: if (type & 8) { ! 311: /* 32 bit */ ! 312: new_cr3 = ldl_kernel(tss_base + 0x1c); ! 313: new_eip = ldl_kernel(tss_base + 0x20); ! 314: new_eflags = ldl_kernel(tss_base + 0x24); ! 315: for(i = 0; i < 8; i++) ! 316: new_regs[i] = ldl_kernel(tss_base + (0x28 + i * 4)); ! 317: for(i = 0; i < 6; i++) ! 318: new_segs[i] = lduw_kernel(tss_base + (0x48 + i * 4)); ! 319: new_ldt = lduw_kernel(tss_base + 0x60); ! 320: new_trap = ldl_kernel(tss_base + 0x64); ! 321: } else { ! 322: /* 16 bit */ ! 323: new_cr3 = 0; ! 324: new_eip = lduw_kernel(tss_base + 0x0e); ! 325: new_eflags = lduw_kernel(tss_base + 0x10); ! 326: for(i = 0; i < 8; i++) ! 327: new_regs[i] = lduw_kernel(tss_base + (0x12 + i * 2)) | 0xffff0000; ! 328: for(i = 0; i < 4; i++) ! 329: new_segs[i] = lduw_kernel(tss_base + (0x22 + i * 4)); ! 330: new_ldt = lduw_kernel(tss_base + 0x2a); ! 331: new_segs[R_FS] = 0; ! 332: new_segs[R_GS] = 0; ! 333: new_trap = 0; ! 334: } ! 335: ! 336: /* NOTE: we must avoid memory exceptions during the task switch, ! 337: so we make dummy accesses before */ ! 338: /* XXX: it can still fail in some cases, so a bigger hack is ! 339: necessary to valid the TLB after having done the accesses */ ! 340: ! 341: v1 = ldub_kernel(env->tr.base); ! 342: v2 = ldub(env->tr.base + old_tss_limit_max); ! 343: stb_kernel(env->tr.base, v1); ! 344: stb_kernel(env->tr.base + old_tss_limit_max, v2); ! 345: ! 346: /* clear busy bit (it is restartable) */ ! 347: if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_IRET) { ! 348: target_ulong ptr; ! 349: uint32_t e2; ! 350: ptr = env->gdt.base + (env->tr.selector & ~7); ! 351: e2 = ldl_kernel(ptr + 4); ! 352: e2 &= ~DESC_TSS_BUSY_MASK; ! 353: stl_kernel(ptr + 4, e2); ! 354: } ! 355: old_eflags = compute_eflags(); ! 356: if (source == SWITCH_TSS_IRET) ! 357: old_eflags &= ~NT_MASK; ! 358: ! 359: /* save the current state in the old TSS */ ! 360: if (type & 8) { ! 361: /* 32 bit */ ! 362: stl_kernel(env->tr.base + 0x20, next_eip); ! 363: stl_kernel(env->tr.base + 0x24, old_eflags); ! 364: stl_kernel(env->tr.base + (0x28 + 0 * 4), EAX); ! 365: stl_kernel(env->tr.base + (0x28 + 1 * 4), ECX); ! 366: stl_kernel(env->tr.base + (0x28 + 2 * 4), EDX); ! 367: stl_kernel(env->tr.base + (0x28 + 3 * 4), EBX); ! 368: stl_kernel(env->tr.base + (0x28 + 4 * 4), ESP); ! 369: stl_kernel(env->tr.base + (0x28 + 5 * 4), EBP); ! 370: stl_kernel(env->tr.base + (0x28 + 6 * 4), ESI); ! 371: stl_kernel(env->tr.base + (0x28 + 7 * 4), EDI); ! 372: for(i = 0; i < 6; i++) ! 373: stw_kernel(env->tr.base + (0x48 + i * 4), env->segs[i].selector); ! 374: } else { ! 375: /* 16 bit */ ! 376: stw_kernel(env->tr.base + 0x0e, next_eip); ! 377: stw_kernel(env->tr.base + 0x10, old_eflags); ! 378: stw_kernel(env->tr.base + (0x12 + 0 * 2), EAX); ! 379: stw_kernel(env->tr.base + (0x12 + 1 * 2), ECX); ! 380: stw_kernel(env->tr.base + (0x12 + 2 * 2), EDX); ! 381: stw_kernel(env->tr.base + (0x12 + 3 * 2), EBX); ! 382: stw_kernel(env->tr.base + (0x12 + 4 * 2), ESP); ! 383: stw_kernel(env->tr.base + (0x12 + 5 * 2), EBP); ! 384: stw_kernel(env->tr.base + (0x12 + 6 * 2), ESI); ! 385: stw_kernel(env->tr.base + (0x12 + 7 * 2), EDI); ! 386: for(i = 0; i < 4; i++) ! 387: stw_kernel(env->tr.base + (0x22 + i * 4), env->segs[i].selector); ! 388: } ! 389: ! 390: /* now if an exception occurs, it will occurs in the next task ! 391: context */ ! 392: ! 393: if (source == SWITCH_TSS_CALL) { ! 394: stw_kernel(tss_base, env->tr.selector); ! 395: new_eflags |= NT_MASK; ! 396: } ! 397: ! 398: /* set busy bit */ ! 399: if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_CALL) { ! 400: target_ulong ptr; ! 401: uint32_t e2; ! 402: ptr = env->gdt.base + (tss_selector & ~7); ! 403: e2 = ldl_kernel(ptr + 4); ! 404: e2 |= DESC_TSS_BUSY_MASK; ! 405: stl_kernel(ptr + 4, e2); ! 406: } ! 407: ! 408: /* set the new CPU state */ ! 409: /* from this point, any exception which occurs can give problems */ ! 410: env->cr[0] |= CR0_TS_MASK; ! 411: env->hflags |= HF_TS_MASK; ! 412: env->tr.selector = tss_selector; ! 413: env->tr.base = tss_base; ! 414: env->tr.limit = tss_limit; ! 415: env->tr.flags = e2 & ~DESC_TSS_BUSY_MASK; ! 416: ! 417: if ((type & 8) && (env->cr[0] & CR0_PG_MASK)) { ! 418: cpu_x86_update_cr3(env, new_cr3); ! 419: } ! 420: ! 421: /* load all registers without an exception, then reload them with ! 422: possible exception */ ! 423: env->eip = new_eip; ! 424: eflags_mask = TF_MASK | AC_MASK | ID_MASK | ! 425: IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | NT_MASK; ! 426: if (!(type & 8)) ! 427: eflags_mask &= 0xffff; ! 428: load_eflags(new_eflags, eflags_mask); ! 429: /* XXX: what to do in 16 bit case ? */ ! 430: EAX = new_regs[0]; ! 431: ECX = new_regs[1]; ! 432: EDX = new_regs[2]; ! 433: EBX = new_regs[3]; ! 434: ESP = new_regs[4]; ! 435: EBP = new_regs[5]; ! 436: ESI = new_regs[6]; ! 437: EDI = new_regs[7]; ! 438: if (new_eflags & VM_MASK) { ! 439: for(i = 0; i < 6; i++) ! 440: load_seg_vm(i, new_segs[i]); ! 441: /* in vm86, CPL is always 3 */ ! 442: cpu_x86_set_cpl(env, 3); ! 443: } else { ! 444: /* CPL is set the RPL of CS */ ! 445: cpu_x86_set_cpl(env, new_segs[R_CS] & 3); ! 446: /* first just selectors as the rest may trigger exceptions */ ! 447: for(i = 0; i < 6; i++) ! 448: cpu_x86_load_seg_cache(env, i, new_segs[i], 0, 0, 0); ! 449: } ! 450: ! 451: env->ldt.selector = new_ldt & ~4; ! 452: env->ldt.base = 0; ! 453: env->ldt.limit = 0; ! 454: env->ldt.flags = 0; ! 455: ! 456: /* load the LDT */ ! 457: if (new_ldt & 4) ! 458: raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc); ! 459: ! 460: if ((new_ldt & 0xfffc) != 0) { ! 461: dt = &env->gdt; ! 462: index = new_ldt & ~7; ! 463: if ((index + 7) > dt->limit) ! 464: raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc); ! 465: ptr = dt->base + index; ! 466: e1 = ldl_kernel(ptr); ! 467: e2 = ldl_kernel(ptr + 4); ! 468: if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2) ! 469: raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc); ! 470: if (!(e2 & DESC_P_MASK)) ! 471: raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc); ! 472: load_seg_cache_raw_dt(&env->ldt, e1, e2); ! 473: } ! 474: ! 475: /* load the segments */ ! 476: if (!(new_eflags & VM_MASK)) { ! 477: tss_load_seg(R_CS, new_segs[R_CS]); ! 478: tss_load_seg(R_SS, new_segs[R_SS]); ! 479: tss_load_seg(R_ES, new_segs[R_ES]); ! 480: tss_load_seg(R_DS, new_segs[R_DS]); ! 481: tss_load_seg(R_FS, new_segs[R_FS]); ! 482: tss_load_seg(R_GS, new_segs[R_GS]); ! 483: } ! 484: ! 485: /* check that EIP is in the CS segment limits */ ! 486: if (new_eip > env->segs[R_CS].limit) { ! 487: /* XXX: different exception if CALL ? */ ! 488: raise_exception_err(EXCP0D_GPF, 0); ! 489: } ! 490: } ! 491: ! 492: /* check if Port I/O is allowed in TSS */ ! 493: static inline void check_io(int addr, int size) ! 494: { ! 495: int io_offset, val, mask; ! 496: ! 497: /* TSS must be a valid 32 bit one */ ! 498: if (!(env->tr.flags & DESC_P_MASK) || ! 499: ((env->tr.flags >> DESC_TYPE_SHIFT) & 0xf) != 9 || ! 500: env->tr.limit < 103) ! 501: goto fail; ! 502: io_offset = lduw_kernel(env->tr.base + 0x66); ! 503: io_offset += (addr >> 3); ! 504: /* Note: the check needs two bytes */ ! 505: if ((io_offset + 1) > env->tr.limit) ! 506: goto fail; ! 507: val = lduw_kernel(env->tr.base + io_offset); ! 508: val >>= (addr & 7); ! 509: mask = (1 << size) - 1; ! 510: /* all bits must be zero to allow the I/O */ ! 511: if ((val & mask) != 0) { ! 512: fail: ! 513: raise_exception_err(EXCP0D_GPF, 0); ! 514: } ! 515: } ! 516: ! 517: void check_iob_T0(void) ! 518: { ! 519: check_io(T0, 1); ! 520: } ! 521: ! 522: void check_iow_T0(void) ! 523: { ! 524: check_io(T0, 2); ! 525: } ! 526: ! 527: void check_iol_T0(void) ! 528: { ! 529: check_io(T0, 4); ! 530: } ! 531: ! 532: void check_iob_DX(void) ! 533: { ! 534: check_io(EDX & 0xffff, 1); ! 535: } ! 536: ! 537: void check_iow_DX(void) ! 538: { ! 539: check_io(EDX & 0xffff, 2); ! 540: } ! 541: ! 542: void check_iol_DX(void) ! 543: { ! 544: check_io(EDX & 0xffff, 4); ! 545: } ! 546: ! 547: static inline unsigned int get_sp_mask(unsigned int e2) ! 548: { ! 549: if (e2 & DESC_B_MASK) ! 550: return 0xffffffff; ! 551: else ! 552: return 0xffff; ! 553: } ! 554: ! 555: /* XXX: add a is_user flag to have proper security support */ ! 556: #define PUSHW(ssp, sp, sp_mask, val)\ ! 557: {\ ! 558: sp -= 2;\ ! 559: stw_kernel((ssp) + (sp & (sp_mask)), (val));\ ! 560: } ! 561: ! 562: #define PUSHL(ssp, sp, sp_mask, val)\ ! 563: {\ ! 564: sp -= 4;\ ! 565: stl_kernel((ssp) + (sp & (sp_mask)), (val));\ ! 566: } ! 567: ! 568: #define POPW(ssp, sp, sp_mask, val)\ ! 569: {\ ! 570: val = lduw_kernel((ssp) + (sp & (sp_mask)));\ ! 571: sp += 2;\ ! 572: } ! 573: ! 574: #define POPL(ssp, sp, sp_mask, val)\ ! 575: {\ ! 576: val = (uint32_t)ldl_kernel((ssp) + (sp & (sp_mask)));\ ! 577: sp += 4;\ ! 578: } ! 579: ! 580: /* protected mode interrupt */ ! 581: static void do_interrupt_protected(int intno, int is_int, int error_code, ! 582: unsigned int next_eip, int is_hw) ! 583: { ! 584: SegmentCache *dt; ! 585: target_ulong ptr, ssp; ! 586: int type, dpl, selector, ss_dpl, cpl, sp_mask; ! 587: int has_error_code, new_stack, shift; ! 588: uint32_t e1, e2, offset, ss, esp, ss_e1, ss_e2; ! 589: uint32_t old_eip; ! 590: ! 591: has_error_code = 0; ! 592: if (!is_int && !is_hw) { ! 593: switch(intno) { ! 594: case 8: ! 595: case 10: ! 596: case 11: ! 597: case 12: ! 598: case 13: ! 599: case 14: ! 600: case 17: ! 601: has_error_code = 1; ! 602: break; ! 603: } ! 604: } ! 605: if (is_int) ! 606: old_eip = next_eip; ! 607: else ! 608: old_eip = env->eip; ! 609: ! 610: dt = &env->idt; ! 611: if (intno * 8 + 7 > dt->limit) ! 612: raise_exception_err(EXCP0D_GPF, intno * 8 + 2); ! 613: ptr = dt->base + intno * 8; ! 614: e1 = ldl_kernel(ptr); ! 615: e2 = ldl_kernel(ptr + 4); ! 616: /* check gate type */ ! 617: type = (e2 >> DESC_TYPE_SHIFT) & 0x1f; ! 618: switch(type) { ! 619: case 5: /* task gate */ ! 620: /* must do that check here to return the correct error code */ ! 621: if (!(e2 & DESC_P_MASK)) ! 622: raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2); ! 623: switch_tss(intno * 8, e1, e2, SWITCH_TSS_CALL, old_eip); ! 624: if (has_error_code) { ! 625: int mask, type; ! 626: /* push the error code */ ! 627: type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf; ! 628: shift = type >> 3; ! 629: if (env->segs[R_SS].flags & DESC_B_MASK) ! 630: mask = 0xffffffff; ! 631: else ! 632: mask = 0xffff; ! 633: esp = (ESP - (2 << shift)) & mask; ! 634: ssp = env->segs[R_SS].base + esp; ! 635: if (shift) ! 636: stl_kernel(ssp, error_code); ! 637: else ! 638: stw_kernel(ssp, error_code); ! 639: ESP = (esp & mask) | (ESP & ~mask); ! 640: } ! 641: return; ! 642: case 6: /* 286 interrupt gate */ ! 643: case 7: /* 286 trap gate */ ! 644: case 14: /* 386 interrupt gate */ ! 645: case 15: /* 386 trap gate */ ! 646: break; ! 647: default: ! 648: raise_exception_err(EXCP0D_GPF, intno * 8 + 2); ! 649: break; ! 650: } ! 651: dpl = (e2 >> DESC_DPL_SHIFT) & 3; ! 652: cpl = env->hflags & HF_CPL_MASK; ! 653: /* check privledge if software int */ ! 654: if (is_int && dpl < cpl) ! 655: raise_exception_err(EXCP0D_GPF, intno * 8 + 2); ! 656: /* check valid bit */ ! 657: if (!(e2 & DESC_P_MASK)) ! 658: raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2); ! 659: selector = e1 >> 16; ! 660: offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff); ! 661: if ((selector & 0xfffc) == 0) ! 662: raise_exception_err(EXCP0D_GPF, 0); ! 663: ! 664: if (load_segment(&e1, &e2, selector) != 0) ! 665: raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ! 666: if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK))) ! 667: raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ! 668: dpl = (e2 >> DESC_DPL_SHIFT) & 3; ! 669: if (dpl > cpl) ! 670: raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ! 671: if (!(e2 & DESC_P_MASK)) ! 672: raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); ! 673: if (!(e2 & DESC_C_MASK) && dpl < cpl) { ! 674: /* to inner priviledge */ ! 675: get_ss_esp_from_tss(&ss, &esp, dpl); ! 676: if ((ss & 0xfffc) == 0) ! 677: raise_exception_err(EXCP0A_TSS, ss & 0xfffc); ! 678: if ((ss & 3) != dpl) ! 679: raise_exception_err(EXCP0A_TSS, ss & 0xfffc); ! 680: if (load_segment(&ss_e1, &ss_e2, ss) != 0) ! 681: raise_exception_err(EXCP0A_TSS, ss & 0xfffc); ! 682: ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3; ! 683: if (ss_dpl != dpl) ! 684: raise_exception_err(EXCP0A_TSS, ss & 0xfffc); ! 685: if (!(ss_e2 & DESC_S_MASK) || ! 686: (ss_e2 & DESC_CS_MASK) || ! 687: !(ss_e2 & DESC_W_MASK)) ! 688: raise_exception_err(EXCP0A_TSS, ss & 0xfffc); ! 689: if (!(ss_e2 & DESC_P_MASK)) ! 690: raise_exception_err(EXCP0A_TSS, ss & 0xfffc); ! 691: new_stack = 1; ! 692: sp_mask = get_sp_mask(ss_e2); ! 693: ssp = get_seg_base(ss_e1, ss_e2); ! 694: } else if ((e2 & DESC_C_MASK) || dpl == cpl) { ! 695: /* to same priviledge */ ! 696: if (env->eflags & VM_MASK) ! 697: raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ! 698: new_stack = 0; ! 699: sp_mask = get_sp_mask(env->segs[R_SS].flags); ! 700: ssp = env->segs[R_SS].base; ! 701: esp = ESP; ! 702: dpl = cpl; ! 703: } else { ! 704: raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ! 705: new_stack = 0; /* avoid warning */ ! 706: sp_mask = 0; /* avoid warning */ ! 707: ssp = 0; /* avoid warning */ ! 708: esp = 0; /* avoid warning */ ! 709: } ! 710: ! 711: shift = type >> 3; ! 712: ! 713: #if 0 ! 714: /* XXX: check that enough room is available */ ! 715: push_size = 6 + (new_stack << 2) + (has_error_code << 1); ! 716: if (env->eflags & VM_MASK) ! 717: push_size += 8; ! 718: push_size <<= shift; ! 719: #endif ! 720: if (shift == 1) { ! 721: if (new_stack) { ! 722: if (env->eflags & VM_MASK) { ! 723: PUSHL(ssp, esp, sp_mask, env->segs[R_GS].selector); ! 724: PUSHL(ssp, esp, sp_mask, env->segs[R_FS].selector); ! 725: PUSHL(ssp, esp, sp_mask, env->segs[R_DS].selector); ! 726: PUSHL(ssp, esp, sp_mask, env->segs[R_ES].selector); ! 727: } ! 728: PUSHL(ssp, esp, sp_mask, env->segs[R_SS].selector); ! 729: PUSHL(ssp, esp, sp_mask, ESP); ! 730: } ! 731: PUSHL(ssp, esp, sp_mask, compute_eflags()); ! 732: PUSHL(ssp, esp, sp_mask, env->segs[R_CS].selector); ! 733: PUSHL(ssp, esp, sp_mask, old_eip); ! 734: if (has_error_code) { ! 735: PUSHL(ssp, esp, sp_mask, error_code); ! 736: } ! 737: } else { ! 738: if (new_stack) { ! 739: if (env->eflags & VM_MASK) { ! 740: PUSHW(ssp, esp, sp_mask, env->segs[R_GS].selector); ! 741: PUSHW(ssp, esp, sp_mask, env->segs[R_FS].selector); ! 742: PUSHW(ssp, esp, sp_mask, env->segs[R_DS].selector); ! 743: PUSHW(ssp, esp, sp_mask, env->segs[R_ES].selector); ! 744: } ! 745: PUSHW(ssp, esp, sp_mask, env->segs[R_SS].selector); ! 746: PUSHW(ssp, esp, sp_mask, ESP); ! 747: } ! 748: PUSHW(ssp, esp, sp_mask, compute_eflags()); ! 749: PUSHW(ssp, esp, sp_mask, env->segs[R_CS].selector); ! 750: PUSHW(ssp, esp, sp_mask, old_eip); ! 751: if (has_error_code) { ! 752: PUSHW(ssp, esp, sp_mask, error_code); ! 753: } ! 754: } ! 755: ! 756: if (new_stack) { ! 757: if (env->eflags & VM_MASK) { ! 758: cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0, 0); ! 759: cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0, 0); ! 760: cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0, 0); ! 761: cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0, 0); ! 762: } ! 763: ss = (ss & ~3) | dpl; ! 764: cpu_x86_load_seg_cache(env, R_SS, ss, ! 765: ssp, get_seg_limit(ss_e1, ss_e2), ss_e2); ! 766: } ! 767: ESP = (ESP & ~sp_mask) | (esp & sp_mask); ! 768: ! 769: selector = (selector & ~3) | dpl; ! 770: cpu_x86_load_seg_cache(env, R_CS, selector, ! 771: get_seg_base(e1, e2), ! 772: get_seg_limit(e1, e2), ! 773: e2); ! 774: cpu_x86_set_cpl(env, dpl); ! 775: env->eip = offset; ! 776: ! 777: /* interrupt gate clear IF mask */ ! 778: if ((type & 1) == 0) { ! 779: env->eflags &= ~IF_MASK; ! 780: } ! 781: env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK); ! 782: } ! 783: ! 784: #ifdef TARGET_X86_64 ! 785: ! 786: #define PUSHQ(sp, val)\ ! 787: {\ ! 788: sp -= 8;\ ! 789: stq_kernel(sp, (val));\ ! 790: } ! 791: ! 792: #define POPQ(sp, val)\ ! 793: {\ ! 794: val = ldq_kernel(sp);\ ! 795: sp += 8;\ ! 796: } ! 797: ! 798: static inline target_ulong get_rsp_from_tss(int level) ! 799: { ! 800: int index; ! 801: ! 802: #if 0 ! 803: printf("TR: base=" TARGET_FMT_lx " limit=%x\n", ! 804: env->tr.base, env->tr.limit); ! 805: #endif ! 806: ! 807: if (!(env->tr.flags & DESC_P_MASK)) ! 808: cpu_abort(env, "invalid tss"); ! 809: index = 8 * level + 4; ! 810: if ((index + 7) > env->tr.limit) ! 811: raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc); ! 812: return ldq_kernel(env->tr.base + index); ! 813: } ! 814: ! 815: /* 64 bit interrupt */ ! 816: static void do_interrupt64(int intno, int is_int, int error_code, ! 817: target_ulong next_eip, int is_hw) ! 818: { ! 819: SegmentCache *dt; ! 820: target_ulong ptr; ! 821: int type, dpl, selector, cpl, ist; ! 822: int has_error_code, new_stack; ! 823: uint32_t e1, e2, e3, ss; ! 824: target_ulong old_eip, esp, offset; ! 825: ! 826: has_error_code = 0; ! 827: if (!is_int && !is_hw) { ! 828: switch(intno) { ! 829: case 8: ! 830: case 10: ! 831: case 11: ! 832: case 12: ! 833: case 13: ! 834: case 14: ! 835: case 17: ! 836: has_error_code = 1; ! 837: break; ! 838: } ! 839: } ! 840: if (is_int) ! 841: old_eip = next_eip; ! 842: else ! 843: old_eip = env->eip; ! 844: ! 845: dt = &env->idt; ! 846: if (intno * 16 + 15 > dt->limit) ! 847: raise_exception_err(EXCP0D_GPF, intno * 16 + 2); ! 848: ptr = dt->base + intno * 16; ! 849: e1 = ldl_kernel(ptr); ! 850: e2 = ldl_kernel(ptr + 4); ! 851: e3 = ldl_kernel(ptr + 8); ! 852: /* check gate type */ ! 853: type = (e2 >> DESC_TYPE_SHIFT) & 0x1f; ! 854: switch(type) { ! 855: case 14: /* 386 interrupt gate */ ! 856: case 15: /* 386 trap gate */ ! 857: break; ! 858: default: ! 859: raise_exception_err(EXCP0D_GPF, intno * 16 + 2); ! 860: break; ! 861: } ! 862: dpl = (e2 >> DESC_DPL_SHIFT) & 3; ! 863: cpl = env->hflags & HF_CPL_MASK; ! 864: /* check privledge if software int */ ! 865: if (is_int && dpl < cpl) ! 866: raise_exception_err(EXCP0D_GPF, intno * 16 + 2); ! 867: /* check valid bit */ ! 868: if (!(e2 & DESC_P_MASK)) ! 869: raise_exception_err(EXCP0B_NOSEG, intno * 16 + 2); ! 870: selector = e1 >> 16; ! 871: offset = ((target_ulong)e3 << 32) | (e2 & 0xffff0000) | (e1 & 0x0000ffff); ! 872: ist = e2 & 7; ! 873: if ((selector & 0xfffc) == 0) ! 874: raise_exception_err(EXCP0D_GPF, 0); ! 875: ! 876: if (load_segment(&e1, &e2, selector) != 0) ! 877: raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ! 878: if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK))) ! 879: raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ! 880: dpl = (e2 >> DESC_DPL_SHIFT) & 3; ! 881: if (dpl > cpl) ! 882: raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ! 883: if (!(e2 & DESC_P_MASK)) ! 884: raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); ! 885: if (!(e2 & DESC_L_MASK) || (e2 & DESC_B_MASK)) ! 886: raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ! 887: if ((!(e2 & DESC_C_MASK) && dpl < cpl) || ist != 0) { ! 888: /* to inner priviledge */ ! 889: if (ist != 0) ! 890: esp = get_rsp_from_tss(ist + 3); ! 891: else ! 892: esp = get_rsp_from_tss(dpl); ! 893: ss = 0; ! 894: new_stack = 1; ! 895: } else if ((e2 & DESC_C_MASK) || dpl == cpl) { ! 896: /* to same priviledge */ ! 897: if (env->eflags & VM_MASK) ! 898: raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ! 899: new_stack = 0; ! 900: esp = ESP & ~0xf; /* align stack */ ! 901: dpl = cpl; ! 902: } else { ! 903: raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ! 904: new_stack = 0; /* avoid warning */ ! 905: esp = 0; /* avoid warning */ ! 906: } ! 907: ! 908: PUSHQ(esp, env->segs[R_SS].selector); ! 909: PUSHQ(esp, ESP); ! 910: PUSHQ(esp, compute_eflags()); ! 911: PUSHQ(esp, env->segs[R_CS].selector); ! 912: PUSHQ(esp, old_eip); ! 913: if (has_error_code) { ! 914: PUSHQ(esp, error_code); ! 915: } ! 916: ! 917: if (new_stack) { ! 918: ss = 0 | dpl; ! 919: cpu_x86_load_seg_cache(env, R_SS, ss, 0, 0, 0); ! 920: } ! 921: ESP = esp; ! 922: ! 923: selector = (selector & ~3) | dpl; ! 924: cpu_x86_load_seg_cache(env, R_CS, selector, ! 925: get_seg_base(e1, e2), ! 926: get_seg_limit(e1, e2), ! 927: e2); ! 928: cpu_x86_set_cpl(env, dpl); ! 929: env->eip = offset; ! 930: ! 931: /* interrupt gate clear IF mask */ ! 932: if ((type & 1) == 0) { ! 933: env->eflags &= ~IF_MASK; ! 934: } ! 935: env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK); ! 936: } ! 937: #endif ! 938: ! 939: void helper_syscall(int next_eip_addend) ! 940: { ! 941: int selector; ! 942: ! 943: if (!(env->efer & MSR_EFER_SCE)) { ! 944: raise_exception_err(EXCP06_ILLOP, 0); ! 945: } ! 946: selector = (env->star >> 32) & 0xffff; ! 947: #ifdef TARGET_X86_64 ! 948: if (env->hflags & HF_LMA_MASK) { ! 949: ECX = env->eip + next_eip_addend; ! 950: env->regs[11] = compute_eflags(); ! 951: ! 952: cpu_x86_set_cpl(env, 0); ! 953: cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc, ! 954: 0, 0xffffffff, ! 955: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | ! 956: DESC_S_MASK | ! 957: DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK); ! 958: cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc, ! 959: 0, 0xffffffff, ! 960: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | ! 961: DESC_S_MASK | ! 962: DESC_W_MASK | DESC_A_MASK); ! 963: env->eflags &= ~env->fmask; ! 964: if (env->hflags & HF_CS64_MASK) ! 965: env->eip = env->lstar; ! 966: else ! 967: env->eip = env->cstar; ! 968: } else ! 969: #endif ! 970: { ! 971: ECX = (uint32_t)(env->eip + next_eip_addend); ! 972: ! 973: cpu_x86_set_cpl(env, 0); ! 974: cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc, ! 975: 0, 0xffffffff, ! 976: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | ! 977: DESC_S_MASK | ! 978: DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); ! 979: cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc, ! 980: 0, 0xffffffff, ! 981: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | ! 982: DESC_S_MASK | ! 983: DESC_W_MASK | DESC_A_MASK); ! 984: env->eflags &= ~(IF_MASK | RF_MASK | VM_MASK); ! 985: env->eip = (uint32_t)env->star; ! 986: } ! 987: } ! 988: ! 989: void helper_sysret(int dflag) ! 990: { ! 991: int cpl, selector; ! 992: ! 993: if (!(env->efer & MSR_EFER_SCE)) { ! 994: raise_exception_err(EXCP06_ILLOP, 0); ! 995: } ! 996: cpl = env->hflags & HF_CPL_MASK; ! 997: if (!(env->cr[0] & CR0_PE_MASK) || cpl != 0) { ! 998: raise_exception_err(EXCP0D_GPF, 0); ! 999: } ! 1000: selector = (env->star >> 48) & 0xffff; ! 1001: #ifdef TARGET_X86_64 ! 1002: if (env->hflags & HF_LMA_MASK) { ! 1003: if (dflag == 2) { ! 1004: cpu_x86_load_seg_cache(env, R_CS, (selector + 16) | 3, ! 1005: 0, 0xffffffff, ! 1006: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | ! 1007: DESC_S_MASK | (3 << DESC_DPL_SHIFT) | ! 1008: DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | ! 1009: DESC_L_MASK); ! 1010: env->eip = ECX; ! 1011: } else { ! 1012: cpu_x86_load_seg_cache(env, R_CS, selector | 3, ! 1013: 0, 0xffffffff, ! 1014: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | ! 1015: DESC_S_MASK | (3 << DESC_DPL_SHIFT) | ! 1016: DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); ! 1017: env->eip = (uint32_t)ECX; ! 1018: } ! 1019: cpu_x86_load_seg_cache(env, R_SS, selector + 8, ! 1020: 0, 0xffffffff, ! 1021: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | ! 1022: DESC_S_MASK | (3 << DESC_DPL_SHIFT) | ! 1023: DESC_W_MASK | DESC_A_MASK); ! 1024: load_eflags((uint32_t)(env->regs[11]), TF_MASK | AC_MASK | ID_MASK | ! 1025: IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | NT_MASK); ! 1026: cpu_x86_set_cpl(env, 3); ! 1027: } else ! 1028: #endif ! 1029: { ! 1030: cpu_x86_load_seg_cache(env, R_CS, selector | 3, ! 1031: 0, 0xffffffff, ! 1032: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | ! 1033: DESC_S_MASK | (3 << DESC_DPL_SHIFT) | ! 1034: DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); ! 1035: env->eip = (uint32_t)ECX; ! 1036: cpu_x86_load_seg_cache(env, R_SS, selector + 8, ! 1037: 0, 0xffffffff, ! 1038: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | ! 1039: DESC_S_MASK | (3 << DESC_DPL_SHIFT) | ! 1040: DESC_W_MASK | DESC_A_MASK); ! 1041: env->eflags |= IF_MASK; ! 1042: cpu_x86_set_cpl(env, 3); ! 1043: } ! 1044: #ifdef USE_KQEMU ! 1045: if (kqemu_is_ok(env)) { ! 1046: if (env->hflags & HF_LMA_MASK) ! 1047: CC_OP = CC_OP_EFLAGS; ! 1048: env->exception_index = -1; ! 1049: cpu_loop_exit(); ! 1050: } ! 1051: #endif ! 1052: } ! 1053: ! 1054: /* real mode interrupt */ ! 1055: static void do_interrupt_real(int intno, int is_int, int error_code, ! 1056: unsigned int next_eip) ! 1057: { ! 1058: SegmentCache *dt; ! 1059: target_ulong ptr, ssp; ! 1060: int selector; ! 1061: uint32_t offset, esp; ! 1062: uint32_t old_cs, old_eip; ! 1063: ! 1064: /* real mode (simpler !) */ ! 1065: dt = &env->idt; ! 1066: if (intno * 4 + 3 > dt->limit) ! 1067: raise_exception_err(EXCP0D_GPF, intno * 8 + 2); ! 1068: ptr = dt->base + intno * 4; ! 1069: offset = lduw_kernel(ptr); ! 1070: selector = lduw_kernel(ptr + 2); ! 1071: esp = ESP; ! 1072: ssp = env->segs[R_SS].base; ! 1073: if (is_int) ! 1074: old_eip = next_eip; ! 1075: else ! 1076: old_eip = env->eip; ! 1077: old_cs = env->segs[R_CS].selector; ! 1078: /* XXX: use SS segment size ? */ ! 1079: PUSHW(ssp, esp, 0xffff, compute_eflags()); ! 1080: PUSHW(ssp, esp, 0xffff, old_cs); ! 1081: PUSHW(ssp, esp, 0xffff, old_eip); ! 1082: ! 1083: /* update processor state */ ! 1084: ESP = (ESP & ~0xffff) | (esp & 0xffff); ! 1085: env->eip = offset; ! 1086: env->segs[R_CS].selector = selector; ! 1087: env->segs[R_CS].base = (selector << 4); ! 1088: env->eflags &= ~(IF_MASK | TF_MASK | AC_MASK | RF_MASK); ! 1089: } ! 1090: ! 1091: /* fake user mode interrupt */ ! 1092: void do_interrupt_user(int intno, int is_int, int error_code, ! 1093: target_ulong next_eip) ! 1094: { ! 1095: SegmentCache *dt; ! 1096: target_ulong ptr; ! 1097: int dpl, cpl; ! 1098: uint32_t e2; ! 1099: ! 1100: dt = &env->idt; ! 1101: ptr = dt->base + (intno * 8); ! 1102: e2 = ldl_kernel(ptr + 4); ! 1103: ! 1104: dpl = (e2 >> DESC_DPL_SHIFT) & 3; ! 1105: cpl = env->hflags & HF_CPL_MASK; ! 1106: /* check privledge if software int */ ! 1107: if (is_int && dpl < cpl) ! 1108: raise_exception_err(EXCP0D_GPF, intno * 8 + 2); ! 1109: ! 1110: /* Since we emulate only user space, we cannot do more than ! 1111: exiting the emulation with the suitable exception and error ! 1112: code */ ! 1113: if (is_int) ! 1114: EIP = next_eip; ! 1115: } ! 1116: ! 1117: /* ! 1118: * Begin execution of an interruption. is_int is TRUE if coming from ! 1119: * the int instruction. next_eip is the EIP value AFTER the interrupt ! 1120: * instruction. It is only relevant if is_int is TRUE. ! 1121: */ ! 1122: void do_interrupt(int intno, int is_int, int error_code, ! 1123: target_ulong next_eip, int is_hw) ! 1124: { ! 1125: #ifdef DEBUG_PCALL ! 1126: if (loglevel & (CPU_LOG_PCALL | CPU_LOG_INT)) { ! 1127: if ((env->cr[0] & CR0_PE_MASK)) { ! 1128: static int count; ! 1129: fprintf(logfile, "%6d: v=%02x e=%04x i=%d cpl=%d IP=%04x:" TARGET_FMT_lx " pc=" TARGET_FMT_lx " SP=%04x:" TARGET_FMT_lx, ! 1130: count, intno, error_code, is_int, ! 1131: env->hflags & HF_CPL_MASK, ! 1132: env->segs[R_CS].selector, EIP, ! 1133: (int)env->segs[R_CS].base + EIP, ! 1134: env->segs[R_SS].selector, ESP); ! 1135: if (intno == 0x0e) { ! 1136: fprintf(logfile, " CR2=" TARGET_FMT_lx, env->cr[2]); ! 1137: } else { ! 1138: fprintf(logfile, " EAX=" TARGET_FMT_lx, EAX); ! 1139: } ! 1140: fprintf(logfile, "\n"); ! 1141: #if 0 ! 1142: cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP); ! 1143: { ! 1144: int i; ! 1145: uint8_t *ptr; ! 1146: fprintf(logfile, " code="); ! 1147: ptr = env->segs[R_CS].base + env->eip; ! 1148: for(i = 0; i < 16; i++) { ! 1149: fprintf(logfile, " %02x", ldub(ptr + i)); ! 1150: } ! 1151: fprintf(logfile, "\n"); ! 1152: } ! 1153: #endif ! 1154: count++; ! 1155: } ! 1156: } ! 1157: #endif ! 1158: if (env->cr[0] & CR0_PE_MASK) { ! 1159: #if TARGET_X86_64 ! 1160: if (env->hflags & HF_LMA_MASK) { ! 1161: do_interrupt64(intno, is_int, error_code, next_eip, is_hw); ! 1162: } else ! 1163: #endif ! 1164: { ! 1165: do_interrupt_protected(intno, is_int, error_code, next_eip, is_hw); ! 1166: } ! 1167: } else { ! 1168: do_interrupt_real(intno, is_int, error_code, next_eip); ! 1169: } ! 1170: } ! 1171: ! 1172: /* ! 1173: * Signal an interruption. It is executed in the main CPU loop. ! 1174: * is_int is TRUE if coming from the int instruction. next_eip is the ! 1175: * EIP value AFTER the interrupt instruction. It is only relevant if ! 1176: * is_int is TRUE. ! 1177: */ ! 1178: void raise_interrupt(int intno, int is_int, int error_code, ! 1179: int next_eip_addend) ! 1180: { ! 1181: env->exception_index = intno; ! 1182: env->error_code = error_code; ! 1183: env->exception_is_int = is_int; ! 1184: env->exception_next_eip = env->eip + next_eip_addend; ! 1185: cpu_loop_exit(); ! 1186: } ! 1187: ! 1188: /* same as raise_exception_err, but do not restore global registers */ ! 1189: static void raise_exception_err_norestore(int exception_index, int error_code) ! 1190: { ! 1191: env->exception_index = exception_index; ! 1192: env->error_code = error_code; ! 1193: env->exception_is_int = 0; ! 1194: env->exception_next_eip = 0; ! 1195: longjmp(env->jmp_env, 1); ! 1196: } ! 1197: ! 1198: /* shortcuts to generate exceptions */ ! 1199: ! 1200: void (raise_exception_err)(int exception_index, int error_code) ! 1201: { ! 1202: raise_interrupt(exception_index, 0, error_code, 0); ! 1203: } ! 1204: ! 1205: void raise_exception(int exception_index) ! 1206: { ! 1207: raise_interrupt(exception_index, 0, 0, 0); ! 1208: } ! 1209: ! 1210: #ifdef BUGGY_GCC_DIV64 ! 1211: /* gcc 2.95.4 on PowerPC does not seem to like using __udivdi3, so we ! 1212: call it from another function */ ! 1213: uint32_t div32(uint64_t *q_ptr, uint64_t num, uint32_t den) ! 1214: { ! 1215: *q_ptr = num / den; ! 1216: return num % den; ! 1217: } ! 1218: ! 1219: int32_t idiv32(int64_t *q_ptr, int64_t num, int32_t den) ! 1220: { ! 1221: *q_ptr = num / den; ! 1222: return num % den; ! 1223: } ! 1224: #endif ! 1225: ! 1226: void helper_divl_EAX_T0(void) ! 1227: { ! 1228: unsigned int den, r; ! 1229: uint64_t num, q; ! 1230: ! 1231: num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32); ! 1232: den = T0; ! 1233: if (den == 0) { ! 1234: raise_exception(EXCP00_DIVZ); ! 1235: } ! 1236: #ifdef BUGGY_GCC_DIV64 ! 1237: r = div32(&q, num, den); ! 1238: #else ! 1239: q = (num / den); ! 1240: r = (num % den); ! 1241: #endif ! 1242: if (q > 0xffffffff) ! 1243: raise_exception(EXCP00_DIVZ); ! 1244: EAX = (uint32_t)q; ! 1245: EDX = (uint32_t)r; ! 1246: } ! 1247: ! 1248: void helper_idivl_EAX_T0(void) ! 1249: { ! 1250: int den, r; ! 1251: int64_t num, q; ! 1252: ! 1253: num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32); ! 1254: den = T0; ! 1255: if (den == 0) { ! 1256: raise_exception(EXCP00_DIVZ); ! 1257: } ! 1258: #ifdef BUGGY_GCC_DIV64 ! 1259: r = idiv32(&q, num, den); ! 1260: #else ! 1261: q = (num / den); ! 1262: r = (num % den); ! 1263: #endif ! 1264: if (q != (int32_t)q) ! 1265: raise_exception(EXCP00_DIVZ); ! 1266: EAX = (uint32_t)q; ! 1267: EDX = (uint32_t)r; ! 1268: } ! 1269: ! 1270: void helper_cmpxchg8b(void) ! 1271: { ! 1272: uint64_t d; ! 1273: int eflags; ! 1274: ! 1275: eflags = cc_table[CC_OP].compute_all(); ! 1276: d = ldq(A0); ! 1277: if (d == (((uint64_t)EDX << 32) | EAX)) { ! 1278: stq(A0, ((uint64_t)ECX << 32) | EBX); ! 1279: eflags |= CC_Z; ! 1280: } else { ! 1281: EDX = d >> 32; ! 1282: EAX = d; ! 1283: eflags &= ~CC_Z; ! 1284: } ! 1285: CC_SRC = eflags; ! 1286: } ! 1287: ! 1288: void helper_cpuid(void) ! 1289: { ! 1290: uint32_t index; ! 1291: index = (uint32_t)EAX; ! 1292: ! 1293: /* test if maximum index reached */ ! 1294: if (index & 0x80000000) { ! 1295: if (index > env->cpuid_xlevel) ! 1296: index = env->cpuid_level; ! 1297: } else { ! 1298: if (index > env->cpuid_level) ! 1299: index = env->cpuid_level; ! 1300: } ! 1301: ! 1302: switch(index) { ! 1303: case 0: ! 1304: EAX = env->cpuid_level; ! 1305: EBX = env->cpuid_vendor1; ! 1306: EDX = env->cpuid_vendor2; ! 1307: ECX = env->cpuid_vendor3; ! 1308: break; ! 1309: case 1: ! 1310: EAX = env->cpuid_version; ! 1311: EBX = 8 << 8; /* CLFLUSH size in quad words, Linux wants it. */ ! 1312: ECX = env->cpuid_ext_features; ! 1313: EDX = env->cpuid_features; ! 1314: break; ! 1315: case 2: ! 1316: /* cache info: needed for Pentium Pro compatibility */ ! 1317: EAX = 0x410601; ! 1318: EBX = 0; ! 1319: ECX = 0; ! 1320: EDX = 0; ! 1321: break; ! 1322: case 0x80000000: ! 1323: EAX = env->cpuid_xlevel; ! 1324: EBX = env->cpuid_vendor1; ! 1325: EDX = env->cpuid_vendor2; ! 1326: ECX = env->cpuid_vendor3; ! 1327: break; ! 1328: case 0x80000001: ! 1329: EAX = env->cpuid_features; ! 1330: EBX = 0; ! 1331: ECX = 0; ! 1332: EDX = env->cpuid_ext2_features; ! 1333: break; ! 1334: case 0x80000002: ! 1335: case 0x80000003: ! 1336: case 0x80000004: ! 1337: EAX = env->cpuid_model[(index - 0x80000002) * 4 + 0]; ! 1338: EBX = env->cpuid_model[(index - 0x80000002) * 4 + 1]; ! 1339: ECX = env->cpuid_model[(index - 0x80000002) * 4 + 2]; ! 1340: EDX = env->cpuid_model[(index - 0x80000002) * 4 + 3]; ! 1341: break; ! 1342: case 0x80000005: ! 1343: /* cache info (L1 cache) */ ! 1344: EAX = 0x01ff01ff; ! 1345: EBX = 0x01ff01ff; ! 1346: ECX = 0x40020140; ! 1347: EDX = 0x40020140; ! 1348: break; ! 1349: case 0x80000006: ! 1350: /* cache info (L2 cache) */ ! 1351: EAX = 0; ! 1352: EBX = 0x42004200; ! 1353: ECX = 0x02008140; ! 1354: EDX = 0; ! 1355: break; ! 1356: case 0x80000008: ! 1357: /* virtual & phys address size in low 2 bytes. */ ! 1358: EAX = 0x00003028; ! 1359: EBX = 0; ! 1360: ECX = 0; ! 1361: EDX = 0; ! 1362: break; ! 1363: default: ! 1364: /* reserved values: zero */ ! 1365: EAX = 0; ! 1366: EBX = 0; ! 1367: ECX = 0; ! 1368: EDX = 0; ! 1369: break; ! 1370: } ! 1371: } ! 1372: ! 1373: void helper_enter_level(int level, int data32) ! 1374: { ! 1375: target_ulong ssp; ! 1376: uint32_t esp_mask, esp, ebp; ! 1377: ! 1378: esp_mask = get_sp_mask(env->segs[R_SS].flags); ! 1379: ssp = env->segs[R_SS].base; ! 1380: ebp = EBP; ! 1381: esp = ESP; ! 1382: if (data32) { ! 1383: /* 32 bit */ ! 1384: esp -= 4; ! 1385: while (--level) { ! 1386: esp -= 4; ! 1387: ebp -= 4; ! 1388: stl(ssp + (esp & esp_mask), ldl(ssp + (ebp & esp_mask))); ! 1389: } ! 1390: esp -= 4; ! 1391: stl(ssp + (esp & esp_mask), T1); ! 1392: } else { ! 1393: /* 16 bit */ ! 1394: esp -= 2; ! 1395: while (--level) { ! 1396: esp -= 2; ! 1397: ebp -= 2; ! 1398: stw(ssp + (esp & esp_mask), lduw(ssp + (ebp & esp_mask))); ! 1399: } ! 1400: esp -= 2; ! 1401: stw(ssp + (esp & esp_mask), T1); ! 1402: } ! 1403: } ! 1404: ! 1405: #ifdef TARGET_X86_64 ! 1406: void helper_enter64_level(int level, int data64) ! 1407: { ! 1408: target_ulong esp, ebp; ! 1409: ebp = EBP; ! 1410: esp = ESP; ! 1411: ! 1412: if (data64) { ! 1413: /* 64 bit */ ! 1414: esp -= 8; ! 1415: while (--level) { ! 1416: esp -= 8; ! 1417: ebp -= 8; ! 1418: stq(esp, ldq(ebp)); ! 1419: } ! 1420: esp -= 8; ! 1421: stq(esp, T1); ! 1422: } else { ! 1423: /* 16 bit */ ! 1424: esp -= 2; ! 1425: while (--level) { ! 1426: esp -= 2; ! 1427: ebp -= 2; ! 1428: stw(esp, lduw(ebp)); ! 1429: } ! 1430: esp -= 2; ! 1431: stw(esp, T1); ! 1432: } ! 1433: } ! 1434: #endif ! 1435: ! 1436: void helper_lldt_T0(void) ! 1437: { ! 1438: int selector; ! 1439: SegmentCache *dt; ! 1440: uint32_t e1, e2; ! 1441: int index, entry_limit; ! 1442: target_ulong ptr; ! 1443: ! 1444: selector = T0 & 0xffff; ! 1445: if ((selector & 0xfffc) == 0) { ! 1446: /* XXX: NULL selector case: invalid LDT */ ! 1447: env->ldt.base = 0; ! 1448: env->ldt.limit = 0; ! 1449: } else { ! 1450: if (selector & 0x4) ! 1451: raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ! 1452: dt = &env->gdt; ! 1453: index = selector & ~7; ! 1454: #ifdef TARGET_X86_64 ! 1455: if (env->hflags & HF_LMA_MASK) ! 1456: entry_limit = 15; ! 1457: else ! 1458: #endif ! 1459: entry_limit = 7; ! 1460: if ((index + entry_limit) > dt->limit) ! 1461: raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ! 1462: ptr = dt->base + index; ! 1463: e1 = ldl_kernel(ptr); ! 1464: e2 = ldl_kernel(ptr + 4); ! 1465: if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2) ! 1466: raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ! 1467: if (!(e2 & DESC_P_MASK)) ! 1468: raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); ! 1469: #ifdef TARGET_X86_64 ! 1470: if (env->hflags & HF_LMA_MASK) { ! 1471: uint32_t e3; ! 1472: e3 = ldl_kernel(ptr + 8); ! 1473: load_seg_cache_raw_dt(&env->ldt, e1, e2); ! 1474: env->ldt.base |= (target_ulong)e3 << 32; ! 1475: } else ! 1476: #endif ! 1477: { ! 1478: load_seg_cache_raw_dt(&env->ldt, e1, e2); ! 1479: } ! 1480: } ! 1481: env->ldt.selector = selector; ! 1482: } ! 1483: ! 1484: void helper_ltr_T0(void) ! 1485: { ! 1486: int selector; ! 1487: SegmentCache *dt; ! 1488: uint32_t e1, e2; ! 1489: int index, type, entry_limit; ! 1490: target_ulong ptr; ! 1491: ! 1492: selector = T0 & 0xffff; ! 1493: if ((selector & 0xfffc) == 0) { ! 1494: /* NULL selector case: invalid TR */ ! 1495: env->tr.base = 0; ! 1496: env->tr.limit = 0; ! 1497: env->tr.flags = 0; ! 1498: } else { ! 1499: if (selector & 0x4) ! 1500: raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ! 1501: dt = &env->gdt; ! 1502: index = selector & ~7; ! 1503: #ifdef TARGET_X86_64 ! 1504: if (env->hflags & HF_LMA_MASK) ! 1505: entry_limit = 15; ! 1506: else ! 1507: #endif ! 1508: entry_limit = 7; ! 1509: if ((index + entry_limit) > dt->limit) ! 1510: raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ! 1511: ptr = dt->base + index; ! 1512: e1 = ldl_kernel(ptr); ! 1513: e2 = ldl_kernel(ptr + 4); ! 1514: type = (e2 >> DESC_TYPE_SHIFT) & 0xf; ! 1515: if ((e2 & DESC_S_MASK) || ! 1516: (type != 1 && type != 9)) ! 1517: raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ! 1518: if (!(e2 & DESC_P_MASK)) ! 1519: raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); ! 1520: #ifdef TARGET_X86_64 ! 1521: if (env->hflags & HF_LMA_MASK) { ! 1522: uint32_t e3; ! 1523: e3 = ldl_kernel(ptr + 8); ! 1524: load_seg_cache_raw_dt(&env->tr, e1, e2); ! 1525: env->tr.base |= (target_ulong)e3 << 32; ! 1526: } else ! 1527: #endif ! 1528: { ! 1529: load_seg_cache_raw_dt(&env->tr, e1, e2); ! 1530: } ! 1531: e2 |= DESC_TSS_BUSY_MASK; ! 1532: stl_kernel(ptr + 4, e2); ! 1533: } ! 1534: env->tr.selector = selector; ! 1535: } ! 1536: ! 1537: /* only works if protected mode and not VM86. seg_reg must be != R_CS */ ! 1538: void load_seg(int seg_reg, int selector) ! 1539: { ! 1540: uint32_t e1, e2; ! 1541: int cpl, dpl, rpl; ! 1542: SegmentCache *dt; ! 1543: int index; ! 1544: target_ulong ptr; ! 1545: ! 1546: selector &= 0xffff; ! 1547: cpl = env->hflags & HF_CPL_MASK; ! 1548: if ((selector & 0xfffc) == 0) { ! 1549: /* null selector case */ ! 1550: if (seg_reg == R_SS ! 1551: #ifdef TARGET_X86_64 ! 1552: && (!(env->hflags & HF_CS64_MASK) || cpl == 3) ! 1553: #endif ! 1554: ) ! 1555: raise_exception_err(EXCP0D_GPF, 0); ! 1556: cpu_x86_load_seg_cache(env, seg_reg, selector, 0, 0, 0); ! 1557: } else { ! 1558: ! 1559: if (selector & 0x4) ! 1560: dt = &env->ldt; ! 1561: else ! 1562: dt = &env->gdt; ! 1563: index = selector & ~7; ! 1564: if ((index + 7) > dt->limit) ! 1565: raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ! 1566: ptr = dt->base + index; ! 1567: e1 = ldl_kernel(ptr); ! 1568: e2 = ldl_kernel(ptr + 4); ! 1569: ! 1570: if (!(e2 & DESC_S_MASK)) ! 1571: raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ! 1572: rpl = selector & 3; ! 1573: dpl = (e2 >> DESC_DPL_SHIFT) & 3; ! 1574: if (seg_reg == R_SS) { ! 1575: /* must be writable segment */ ! 1576: if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK)) ! 1577: raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ! 1578: if (rpl != cpl || dpl != cpl) ! 1579: raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ! 1580: } else { ! 1581: /* must be readable segment */ ! 1582: if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) ! 1583: raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ! 1584: ! 1585: if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) { ! 1586: /* if not conforming code, test rights */ ! 1587: if (dpl < cpl || dpl < rpl) ! 1588: raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ! 1589: } ! 1590: } ! 1591: ! 1592: if (!(e2 & DESC_P_MASK)) { ! 1593: if (seg_reg == R_SS) ! 1594: raise_exception_err(EXCP0C_STACK, selector & 0xfffc); ! 1595: else ! 1596: raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); ! 1597: } ! 1598: ! 1599: /* set the access bit if not already set */ ! 1600: if (!(e2 & DESC_A_MASK)) { ! 1601: e2 |= DESC_A_MASK; ! 1602: stl_kernel(ptr + 4, e2); ! 1603: } ! 1604: ! 1605: cpu_x86_load_seg_cache(env, seg_reg, selector, ! 1606: get_seg_base(e1, e2), ! 1607: get_seg_limit(e1, e2), ! 1608: e2); ! 1609: #if 0 ! 1610: fprintf(logfile, "load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx flags=%08x\n", ! 1611: selector, (unsigned long)sc->base, sc->limit, sc->flags); ! 1612: #endif ! 1613: } ! 1614: } ! 1615: ! 1616: /* protected mode jump */ ! 1617: void helper_ljmp_protected_T0_T1(int next_eip_addend) ! 1618: { ! 1619: int new_cs, gate_cs, type; ! 1620: uint32_t e1, e2, cpl, dpl, rpl, limit; ! 1621: target_ulong new_eip, next_eip; ! 1622: ! 1623: new_cs = T0; ! 1624: new_eip = T1; ! 1625: if ((new_cs & 0xfffc) == 0) ! 1626: raise_exception_err(EXCP0D_GPF, 0); ! 1627: if (load_segment(&e1, &e2, new_cs) != 0) ! 1628: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); ! 1629: cpl = env->hflags & HF_CPL_MASK; ! 1630: if (e2 & DESC_S_MASK) { ! 1631: if (!(e2 & DESC_CS_MASK)) ! 1632: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); ! 1633: dpl = (e2 >> DESC_DPL_SHIFT) & 3; ! 1634: if (e2 & DESC_C_MASK) { ! 1635: /* conforming code segment */ ! 1636: if (dpl > cpl) ! 1637: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); ! 1638: } else { ! 1639: /* non conforming code segment */ ! 1640: rpl = new_cs & 3; ! 1641: if (rpl > cpl) ! 1642: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); ! 1643: if (dpl != cpl) ! 1644: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); ! 1645: } ! 1646: if (!(e2 & DESC_P_MASK)) ! 1647: raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); ! 1648: limit = get_seg_limit(e1, e2); ! 1649: if (new_eip > limit && ! 1650: !(env->hflags & HF_LMA_MASK) && !(e2 & DESC_L_MASK)) ! 1651: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); ! 1652: cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl, ! 1653: get_seg_base(e1, e2), limit, e2); ! 1654: EIP = new_eip; ! 1655: } else { ! 1656: /* jump to call or task gate */ ! 1657: dpl = (e2 >> DESC_DPL_SHIFT) & 3; ! 1658: rpl = new_cs & 3; ! 1659: cpl = env->hflags & HF_CPL_MASK; ! 1660: type = (e2 >> DESC_TYPE_SHIFT) & 0xf; ! 1661: switch(type) { ! 1662: case 1: /* 286 TSS */ ! 1663: case 9: /* 386 TSS */ ! 1664: case 5: /* task gate */ ! 1665: if (dpl < cpl || dpl < rpl) ! 1666: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); ! 1667: next_eip = env->eip + next_eip_addend; ! 1668: switch_tss(new_cs, e1, e2, SWITCH_TSS_JMP, next_eip); ! 1669: break; ! 1670: case 4: /* 286 call gate */ ! 1671: case 12: /* 386 call gate */ ! 1672: if ((dpl < cpl) || (dpl < rpl)) ! 1673: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); ! 1674: if (!(e2 & DESC_P_MASK)) ! 1675: raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); ! 1676: gate_cs = e1 >> 16; ! 1677: new_eip = (e1 & 0xffff); ! 1678: if (type == 12) ! 1679: new_eip |= (e2 & 0xffff0000); ! 1680: if (load_segment(&e1, &e2, gate_cs) != 0) ! 1681: raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc); ! 1682: dpl = (e2 >> DESC_DPL_SHIFT) & 3; ! 1683: /* must be code segment */ ! 1684: if (((e2 & (DESC_S_MASK | DESC_CS_MASK)) != ! 1685: (DESC_S_MASK | DESC_CS_MASK))) ! 1686: raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc); ! 1687: if (((e2 & DESC_C_MASK) && (dpl > cpl)) || ! 1688: (!(e2 & DESC_C_MASK) && (dpl != cpl))) ! 1689: raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc); ! 1690: if (!(e2 & DESC_P_MASK)) ! 1691: raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc); ! 1692: limit = get_seg_limit(e1, e2); ! 1693: if (new_eip > limit) ! 1694: raise_exception_err(EXCP0D_GPF, 0); ! 1695: cpu_x86_load_seg_cache(env, R_CS, (gate_cs & 0xfffc) | cpl, ! 1696: get_seg_base(e1, e2), limit, e2); ! 1697: EIP = new_eip; ! 1698: break; ! 1699: default: ! 1700: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); ! 1701: break; ! 1702: } ! 1703: } ! 1704: } ! 1705: ! 1706: /* real mode call */ ! 1707: void helper_lcall_real_T0_T1(int shift, int next_eip) ! 1708: { ! 1709: int new_cs, new_eip; ! 1710: uint32_t esp, esp_mask; ! 1711: target_ulong ssp; ! 1712: ! 1713: new_cs = T0; ! 1714: new_eip = T1; ! 1715: esp = ESP; ! 1716: esp_mask = get_sp_mask(env->segs[R_SS].flags); ! 1717: ssp = env->segs[R_SS].base; ! 1718: if (shift) { ! 1719: PUSHL(ssp, esp, esp_mask, env->segs[R_CS].selector); ! 1720: PUSHL(ssp, esp, esp_mask, next_eip); ! 1721: } else { ! 1722: PUSHW(ssp, esp, esp_mask, env->segs[R_CS].selector); ! 1723: PUSHW(ssp, esp, esp_mask, next_eip); ! 1724: } ! 1725: ! 1726: ESP = (ESP & ~esp_mask) | (esp & esp_mask); ! 1727: env->eip = new_eip; ! 1728: env->segs[R_CS].selector = new_cs; ! 1729: env->segs[R_CS].base = (new_cs << 4); ! 1730: } ! 1731: ! 1732: /* protected mode call */ ! 1733: void helper_lcall_protected_T0_T1(int shift, int next_eip_addend) ! 1734: { ! 1735: int new_cs, new_eip, new_stack, i; ! 1736: uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count; ! 1737: uint32_t ss, ss_e1, ss_e2, sp, type, ss_dpl, sp_mask; ! 1738: uint32_t val, limit, old_sp_mask; ! 1739: target_ulong ssp, old_ssp, next_eip; ! 1740: ! 1741: new_cs = T0; ! 1742: new_eip = T1; ! 1743: next_eip = env->eip + next_eip_addend; ! 1744: #ifdef DEBUG_PCALL ! 1745: if (loglevel & CPU_LOG_PCALL) { ! 1746: fprintf(logfile, "lcall %04x:%08x s=%d\n", ! 1747: new_cs, new_eip, shift); ! 1748: cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP); ! 1749: } ! 1750: #endif ! 1751: if ((new_cs & 0xfffc) == 0) ! 1752: raise_exception_err(EXCP0D_GPF, 0); ! 1753: if (load_segment(&e1, &e2, new_cs) != 0) ! 1754: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); ! 1755: cpl = env->hflags & HF_CPL_MASK; ! 1756: #ifdef DEBUG_PCALL ! 1757: if (loglevel & CPU_LOG_PCALL) { ! 1758: fprintf(logfile, "desc=%08x:%08x\n", e1, e2); ! 1759: } ! 1760: #endif ! 1761: if (e2 & DESC_S_MASK) { ! 1762: if (!(e2 & DESC_CS_MASK)) ! 1763: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); ! 1764: dpl = (e2 >> DESC_DPL_SHIFT) & 3; ! 1765: if (e2 & DESC_C_MASK) { ! 1766: /* conforming code segment */ ! 1767: if (dpl > cpl) ! 1768: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); ! 1769: } else { ! 1770: /* non conforming code segment */ ! 1771: rpl = new_cs & 3; ! 1772: if (rpl > cpl) ! 1773: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); ! 1774: if (dpl != cpl) ! 1775: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); ! 1776: } ! 1777: if (!(e2 & DESC_P_MASK)) ! 1778: raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); ! 1779: ! 1780: #ifdef TARGET_X86_64 ! 1781: /* XXX: check 16/32 bit cases in long mode */ ! 1782: if (shift == 2) { ! 1783: target_ulong rsp; ! 1784: /* 64 bit case */ ! 1785: rsp = ESP; ! 1786: PUSHQ(rsp, env->segs[R_CS].selector); ! 1787: PUSHQ(rsp, next_eip); ! 1788: /* from this point, not restartable */ ! 1789: ESP = rsp; ! 1790: cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl, ! 1791: get_seg_base(e1, e2), ! 1792: get_seg_limit(e1, e2), e2); ! 1793: EIP = new_eip; ! 1794: } else ! 1795: #endif ! 1796: { ! 1797: sp = ESP; ! 1798: sp_mask = get_sp_mask(env->segs[R_SS].flags); ! 1799: ssp = env->segs[R_SS].base; ! 1800: if (shift) { ! 1801: PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector); ! 1802: PUSHL(ssp, sp, sp_mask, next_eip); ! 1803: } else { ! 1804: PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector); ! 1805: PUSHW(ssp, sp, sp_mask, next_eip); ! 1806: } ! 1807: ! 1808: limit = get_seg_limit(e1, e2); ! 1809: if (new_eip > limit) ! 1810: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); ! 1811: /* from this point, not restartable */ ! 1812: ESP = (ESP & ~sp_mask) | (sp & sp_mask); ! 1813: cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl, ! 1814: get_seg_base(e1, e2), limit, e2); ! 1815: EIP = new_eip; ! 1816: } ! 1817: } else { ! 1818: /* check gate type */ ! 1819: type = (e2 >> DESC_TYPE_SHIFT) & 0x1f; ! 1820: dpl = (e2 >> DESC_DPL_SHIFT) & 3; ! 1821: rpl = new_cs & 3; ! 1822: switch(type) { ! 1823: case 1: /* available 286 TSS */ ! 1824: case 9: /* available 386 TSS */ ! 1825: case 5: /* task gate */ ! 1826: if (dpl < cpl || dpl < rpl) ! 1827: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); ! 1828: switch_tss(new_cs, e1, e2, SWITCH_TSS_CALL, next_eip); ! 1829: return; ! 1830: case 4: /* 286 call gate */ ! 1831: case 12: /* 386 call gate */ ! 1832: break; ! 1833: default: ! 1834: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); ! 1835: break; ! 1836: } ! 1837: shift = type >> 3; ! 1838: ! 1839: if (dpl < cpl || dpl < rpl) ! 1840: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); ! 1841: /* check valid bit */ ! 1842: if (!(e2 & DESC_P_MASK)) ! 1843: raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); ! 1844: selector = e1 >> 16; ! 1845: offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff); ! 1846: param_count = e2 & 0x1f; ! 1847: if ((selector & 0xfffc) == 0) ! 1848: raise_exception_err(EXCP0D_GPF, 0); ! 1849: ! 1850: if (load_segment(&e1, &e2, selector) != 0) ! 1851: raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ! 1852: if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK))) ! 1853: raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ! 1854: dpl = (e2 >> DESC_DPL_SHIFT) & 3; ! 1855: if (dpl > cpl) ! 1856: raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ! 1857: if (!(e2 & DESC_P_MASK)) ! 1858: raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); ! 1859: ! 1860: if (!(e2 & DESC_C_MASK) && dpl < cpl) { ! 1861: /* to inner priviledge */ ! 1862: get_ss_esp_from_tss(&ss, &sp, dpl); ! 1863: #ifdef DEBUG_PCALL ! 1864: if (loglevel & CPU_LOG_PCALL) ! 1865: fprintf(logfile, "new ss:esp=%04x:%08x param_count=%d ESP=" TARGET_FMT_lx "\n", ! 1866: ss, sp, param_count, ESP); ! 1867: #endif ! 1868: if ((ss & 0xfffc) == 0) ! 1869: raise_exception_err(EXCP0A_TSS, ss & 0xfffc); ! 1870: if ((ss & 3) != dpl) ! 1871: raise_exception_err(EXCP0A_TSS, ss & 0xfffc); ! 1872: if (load_segment(&ss_e1, &ss_e2, ss) != 0) ! 1873: raise_exception_err(EXCP0A_TSS, ss & 0xfffc); ! 1874: ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3; ! 1875: if (ss_dpl != dpl) ! 1876: raise_exception_err(EXCP0A_TSS, ss & 0xfffc); ! 1877: if (!(ss_e2 & DESC_S_MASK) || ! 1878: (ss_e2 & DESC_CS_MASK) || ! 1879: !(ss_e2 & DESC_W_MASK)) ! 1880: raise_exception_err(EXCP0A_TSS, ss & 0xfffc); ! 1881: if (!(ss_e2 & DESC_P_MASK)) ! 1882: raise_exception_err(EXCP0A_TSS, ss & 0xfffc); ! 1883: ! 1884: // push_size = ((param_count * 2) + 8) << shift; ! 1885: ! 1886: old_sp_mask = get_sp_mask(env->segs[R_SS].flags); ! 1887: old_ssp = env->segs[R_SS].base; ! 1888: ! 1889: sp_mask = get_sp_mask(ss_e2); ! 1890: ssp = get_seg_base(ss_e1, ss_e2); ! 1891: if (shift) { ! 1892: PUSHL(ssp, sp, sp_mask, env->segs[R_SS].selector); ! 1893: PUSHL(ssp, sp, sp_mask, ESP); ! 1894: for(i = param_count - 1; i >= 0; i--) { ! 1895: val = ldl_kernel(old_ssp + ((ESP + i * 4) & old_sp_mask)); ! 1896: PUSHL(ssp, sp, sp_mask, val); ! 1897: } ! 1898: } else { ! 1899: PUSHW(ssp, sp, sp_mask, env->segs[R_SS].selector); ! 1900: PUSHW(ssp, sp, sp_mask, ESP); ! 1901: for(i = param_count - 1; i >= 0; i--) { ! 1902: val = lduw_kernel(old_ssp + ((ESP + i * 2) & old_sp_mask)); ! 1903: PUSHW(ssp, sp, sp_mask, val); ! 1904: } ! 1905: } ! 1906: new_stack = 1; ! 1907: } else { ! 1908: /* to same priviledge */ ! 1909: sp = ESP; ! 1910: sp_mask = get_sp_mask(env->segs[R_SS].flags); ! 1911: ssp = env->segs[R_SS].base; ! 1912: // push_size = (4 << shift); ! 1913: new_stack = 0; ! 1914: } ! 1915: ! 1916: if (shift) { ! 1917: PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector); ! 1918: PUSHL(ssp, sp, sp_mask, next_eip); ! 1919: } else { ! 1920: PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector); ! 1921: PUSHW(ssp, sp, sp_mask, next_eip); ! 1922: } ! 1923: ! 1924: /* from this point, not restartable */ ! 1925: ! 1926: if (new_stack) { ! 1927: ss = (ss & ~3) | dpl; ! 1928: cpu_x86_load_seg_cache(env, R_SS, ss, ! 1929: ssp, ! 1930: get_seg_limit(ss_e1, ss_e2), ! 1931: ss_e2); ! 1932: } ! 1933: ! 1934: selector = (selector & ~3) | dpl; ! 1935: cpu_x86_load_seg_cache(env, R_CS, selector, ! 1936: get_seg_base(e1, e2), ! 1937: get_seg_limit(e1, e2), ! 1938: e2); ! 1939: cpu_x86_set_cpl(env, dpl); ! 1940: ESP = (ESP & ~sp_mask) | (sp & sp_mask); ! 1941: EIP = offset; ! 1942: } ! 1943: #ifdef USE_KQEMU ! 1944: if (kqemu_is_ok(env)) { ! 1945: env->exception_index = -1; ! 1946: cpu_loop_exit(); ! 1947: } ! 1948: #endif ! 1949: } ! 1950: ! 1951: /* real and vm86 mode iret */ ! 1952: void helper_iret_real(int shift) ! 1953: { ! 1954: uint32_t sp, new_cs, new_eip, new_eflags, sp_mask; ! 1955: target_ulong ssp; ! 1956: int eflags_mask; ! 1957: ! 1958: sp_mask = 0xffff; /* XXXX: use SS segment size ? */ ! 1959: sp = ESP; ! 1960: ssp = env->segs[R_SS].base; ! 1961: if (shift == 1) { ! 1962: /* 32 bits */ ! 1963: POPL(ssp, sp, sp_mask, new_eip); ! 1964: POPL(ssp, sp, sp_mask, new_cs); ! 1965: new_cs &= 0xffff; ! 1966: POPL(ssp, sp, sp_mask, new_eflags); ! 1967: } else { ! 1968: /* 16 bits */ ! 1969: POPW(ssp, sp, sp_mask, new_eip); ! 1970: POPW(ssp, sp, sp_mask, new_cs); ! 1971: POPW(ssp, sp, sp_mask, new_eflags); ! 1972: } ! 1973: ESP = (ESP & ~sp_mask) | (sp & sp_mask); ! 1974: load_seg_vm(R_CS, new_cs); ! 1975: env->eip = new_eip; ! 1976: if (env->eflags & VM_MASK) ! 1977: eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | RF_MASK | NT_MASK; ! 1978: else ! 1979: eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | IOPL_MASK | RF_MASK | NT_MASK; ! 1980: if (shift == 0) ! 1981: eflags_mask &= 0xffff; ! 1982: load_eflags(new_eflags, eflags_mask); ! 1983: } ! 1984: ! 1985: static inline void validate_seg(int seg_reg, int cpl) ! 1986: { ! 1987: int dpl; ! 1988: uint32_t e2; ! 1989: ! 1990: e2 = env->segs[seg_reg].flags; ! 1991: dpl = (e2 >> DESC_DPL_SHIFT) & 3; ! 1992: if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) { ! 1993: /* data or non conforming code segment */ ! 1994: if (dpl < cpl) { ! 1995: cpu_x86_load_seg_cache(env, seg_reg, 0, 0, 0, 0); ! 1996: } ! 1997: } ! 1998: } ! 1999: ! 2000: /* protected mode iret */ ! 2001: static inline void helper_ret_protected(int shift, int is_iret, int addend) ! 2002: { ! 2003: uint32_t new_cs, new_eflags, new_ss; ! 2004: uint32_t new_es, new_ds, new_fs, new_gs; ! 2005: uint32_t e1, e2, ss_e1, ss_e2; ! 2006: int cpl, dpl, rpl, eflags_mask, iopl; ! 2007: target_ulong ssp, sp, new_eip, new_esp, sp_mask; ! 2008: ! 2009: #ifdef TARGET_X86_64 ! 2010: if (shift == 2) ! 2011: sp_mask = -1; ! 2012: else ! 2013: #endif ! 2014: sp_mask = get_sp_mask(env->segs[R_SS].flags); ! 2015: sp = ESP; ! 2016: ssp = env->segs[R_SS].base; ! 2017: new_eflags = 0; /* avoid warning */ ! 2018: #ifdef TARGET_X86_64 ! 2019: if (shift == 2) { ! 2020: POPQ(sp, new_eip); ! 2021: POPQ(sp, new_cs); ! 2022: new_cs &= 0xffff; ! 2023: if (is_iret) { ! 2024: POPQ(sp, new_eflags); ! 2025: } ! 2026: } else ! 2027: #endif ! 2028: if (shift == 1) { ! 2029: /* 32 bits */ ! 2030: POPL(ssp, sp, sp_mask, new_eip); ! 2031: POPL(ssp, sp, sp_mask, new_cs); ! 2032: new_cs &= 0xffff; ! 2033: if (is_iret) { ! 2034: POPL(ssp, sp, sp_mask, new_eflags); ! 2035: if (new_eflags & VM_MASK) ! 2036: goto return_to_vm86; ! 2037: } ! 2038: } else { ! 2039: /* 16 bits */ ! 2040: POPW(ssp, sp, sp_mask, new_eip); ! 2041: POPW(ssp, sp, sp_mask, new_cs); ! 2042: if (is_iret) ! 2043: POPW(ssp, sp, sp_mask, new_eflags); ! 2044: } ! 2045: #ifdef DEBUG_PCALL ! 2046: if (loglevel & CPU_LOG_PCALL) { ! 2047: fprintf(logfile, "lret new %04x:" TARGET_FMT_lx " s=%d addend=0x%x\n", ! 2048: new_cs, new_eip, shift, addend); ! 2049: cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP); ! 2050: } ! 2051: #endif ! 2052: if ((new_cs & 0xfffc) == 0) ! 2053: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); ! 2054: if (load_segment(&e1, &e2, new_cs) != 0) ! 2055: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); ! 2056: if (!(e2 & DESC_S_MASK) || ! 2057: !(e2 & DESC_CS_MASK)) ! 2058: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); ! 2059: cpl = env->hflags & HF_CPL_MASK; ! 2060: rpl = new_cs & 3; ! 2061: if (rpl < cpl) ! 2062: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); ! 2063: dpl = (e2 >> DESC_DPL_SHIFT) & 3; ! 2064: if (e2 & DESC_C_MASK) { ! 2065: if (dpl > rpl) ! 2066: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); ! 2067: } else { ! 2068: if (dpl != rpl) ! 2069: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); ! 2070: } ! 2071: if (!(e2 & DESC_P_MASK)) ! 2072: raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); ! 2073: ! 2074: sp += addend; ! 2075: if (rpl == cpl && (!(env->hflags & HF_CS64_MASK) || ! 2076: ((env->hflags & HF_CS64_MASK) && !is_iret))) { ! 2077: /* return to same priledge level */ ! 2078: cpu_x86_load_seg_cache(env, R_CS, new_cs, ! 2079: get_seg_base(e1, e2), ! 2080: get_seg_limit(e1, e2), ! 2081: e2); ! 2082: } else { ! 2083: /* return to different priviledge level */ ! 2084: #ifdef TARGET_X86_64 ! 2085: if (shift == 2) { ! 2086: POPQ(sp, new_esp); ! 2087: POPQ(sp, new_ss); ! 2088: new_ss &= 0xffff; ! 2089: } else ! 2090: #endif ! 2091: if (shift == 1) { ! 2092: /* 32 bits */ ! 2093: POPL(ssp, sp, sp_mask, new_esp); ! 2094: POPL(ssp, sp, sp_mask, new_ss); ! 2095: new_ss &= 0xffff; ! 2096: } else { ! 2097: /* 16 bits */ ! 2098: POPW(ssp, sp, sp_mask, new_esp); ! 2099: POPW(ssp, sp, sp_mask, new_ss); ! 2100: } ! 2101: #ifdef DEBUG_PCALL ! 2102: if (loglevel & CPU_LOG_PCALL) { ! 2103: fprintf(logfile, "new ss:esp=%04x:" TARGET_FMT_lx "\n", ! 2104: new_ss, new_esp); ! 2105: } ! 2106: #endif ! 2107: if ((new_ss & 0xfffc) == 0) { ! 2108: #ifdef TARGET_X86_64 ! 2109: /* NULL ss is allowed in long mode if cpl != 3*/ ! 2110: if ((env->hflags & HF_LMA_MASK) && rpl != 3) { ! 2111: cpu_x86_load_seg_cache(env, R_SS, new_ss, ! 2112: 0, 0xffffffff, ! 2113: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | ! 2114: DESC_S_MASK | (rpl << DESC_DPL_SHIFT) | ! 2115: DESC_W_MASK | DESC_A_MASK); ! 2116: } else ! 2117: #endif ! 2118: { ! 2119: raise_exception_err(EXCP0D_GPF, 0); ! 2120: } ! 2121: } else { ! 2122: if ((new_ss & 3) != rpl) ! 2123: raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); ! 2124: if (load_segment(&ss_e1, &ss_e2, new_ss) != 0) ! 2125: raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); ! 2126: if (!(ss_e2 & DESC_S_MASK) || ! 2127: (ss_e2 & DESC_CS_MASK) || ! 2128: !(ss_e2 & DESC_W_MASK)) ! 2129: raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); ! 2130: dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3; ! 2131: if (dpl != rpl) ! 2132: raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); ! 2133: if (!(ss_e2 & DESC_P_MASK)) ! 2134: raise_exception_err(EXCP0B_NOSEG, new_ss & 0xfffc); ! 2135: cpu_x86_load_seg_cache(env, R_SS, new_ss, ! 2136: get_seg_base(ss_e1, ss_e2), ! 2137: get_seg_limit(ss_e1, ss_e2), ! 2138: ss_e2); ! 2139: } ! 2140: ! 2141: cpu_x86_load_seg_cache(env, R_CS, new_cs, ! 2142: get_seg_base(e1, e2), ! 2143: get_seg_limit(e1, e2), ! 2144: e2); ! 2145: cpu_x86_set_cpl(env, rpl); ! 2146: sp = new_esp; ! 2147: #ifdef TARGET_X86_64 ! 2148: if (env->hflags & HF_CS64_MASK) ! 2149: sp_mask = -1; ! 2150: else ! 2151: #endif ! 2152: sp_mask = get_sp_mask(ss_e2); ! 2153: ! 2154: /* validate data segments */ ! 2155: validate_seg(R_ES, cpl); ! 2156: validate_seg(R_DS, cpl); ! 2157: validate_seg(R_FS, cpl); ! 2158: validate_seg(R_GS, cpl); ! 2159: ! 2160: sp += addend; ! 2161: } ! 2162: ESP = (ESP & ~sp_mask) | (sp & sp_mask); ! 2163: env->eip = new_eip; ! 2164: if (is_iret) { ! 2165: /* NOTE: 'cpl' is the _old_ CPL */ ! 2166: eflags_mask = TF_MASK | AC_MASK | ID_MASK | RF_MASK | NT_MASK; ! 2167: if (cpl == 0) ! 2168: eflags_mask |= IOPL_MASK; ! 2169: iopl = (env->eflags >> IOPL_SHIFT) & 3; ! 2170: if (cpl <= iopl) ! 2171: eflags_mask |= IF_MASK; ! 2172: if (shift == 0) ! 2173: eflags_mask &= 0xffff; ! 2174: load_eflags(new_eflags, eflags_mask); ! 2175: } ! 2176: return; ! 2177: ! 2178: return_to_vm86: ! 2179: POPL(ssp, sp, sp_mask, new_esp); ! 2180: POPL(ssp, sp, sp_mask, new_ss); ! 2181: POPL(ssp, sp, sp_mask, new_es); ! 2182: POPL(ssp, sp, sp_mask, new_ds); ! 2183: POPL(ssp, sp, sp_mask, new_fs); ! 2184: POPL(ssp, sp, sp_mask, new_gs); ! 2185: ! 2186: /* modify processor state */ ! 2187: load_eflags(new_eflags, TF_MASK | AC_MASK | ID_MASK | ! 2188: IF_MASK | IOPL_MASK | VM_MASK | NT_MASK | VIF_MASK | VIP_MASK); ! 2189: load_seg_vm(R_CS, new_cs & 0xffff); ! 2190: cpu_x86_set_cpl(env, 3); ! 2191: load_seg_vm(R_SS, new_ss & 0xffff); ! 2192: load_seg_vm(R_ES, new_es & 0xffff); ! 2193: load_seg_vm(R_DS, new_ds & 0xffff); ! 2194: load_seg_vm(R_FS, new_fs & 0xffff); ! 2195: load_seg_vm(R_GS, new_gs & 0xffff); ! 2196: ! 2197: env->eip = new_eip & 0xffff; ! 2198: ESP = new_esp; ! 2199: } ! 2200: ! 2201: void helper_iret_protected(int shift, int next_eip) ! 2202: { ! 2203: int tss_selector, type; ! 2204: uint32_t e1, e2; ! 2205: ! 2206: /* specific case for TSS */ ! 2207: if (env->eflags & NT_MASK) { ! 2208: #ifdef TARGET_X86_64 ! 2209: if (env->hflags & HF_LMA_MASK) ! 2210: raise_exception_err(EXCP0D_GPF, 0); ! 2211: #endif ! 2212: tss_selector = lduw_kernel(env->tr.base + 0); ! 2213: if (tss_selector & 4) ! 2214: raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc); ! 2215: if (load_segment(&e1, &e2, tss_selector) != 0) ! 2216: raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc); ! 2217: type = (e2 >> DESC_TYPE_SHIFT) & 0x17; ! 2218: /* NOTE: we check both segment and busy TSS */ ! 2219: if (type != 3) ! 2220: raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc); ! 2221: switch_tss(tss_selector, e1, e2, SWITCH_TSS_IRET, next_eip); ! 2222: } else { ! 2223: helper_ret_protected(shift, 1, 0); ! 2224: } ! 2225: #ifdef USE_KQEMU ! 2226: if (kqemu_is_ok(env)) { ! 2227: CC_OP = CC_OP_EFLAGS; ! 2228: env->exception_index = -1; ! 2229: cpu_loop_exit(); ! 2230: } ! 2231: #endif ! 2232: } ! 2233: ! 2234: void helper_lret_protected(int shift, int addend) ! 2235: { ! 2236: helper_ret_protected(shift, 0, addend); ! 2237: #ifdef USE_KQEMU ! 2238: if (kqemu_is_ok(env)) { ! 2239: env->exception_index = -1; ! 2240: cpu_loop_exit(); ! 2241: } ! 2242: #endif ! 2243: } ! 2244: ! 2245: void helper_sysenter(void) ! 2246: { ! 2247: if (env->sysenter_cs == 0) { ! 2248: raise_exception_err(EXCP0D_GPF, 0); ! 2249: } ! 2250: env->eflags &= ~(VM_MASK | IF_MASK | RF_MASK); ! 2251: cpu_x86_set_cpl(env, 0); ! 2252: cpu_x86_load_seg_cache(env, R_CS, env->sysenter_cs & 0xfffc, ! 2253: 0, 0xffffffff, ! 2254: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | ! 2255: DESC_S_MASK | ! 2256: DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); ! 2257: cpu_x86_load_seg_cache(env, R_SS, (env->sysenter_cs + 8) & 0xfffc, ! 2258: 0, 0xffffffff, ! 2259: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | ! 2260: DESC_S_MASK | ! 2261: DESC_W_MASK | DESC_A_MASK); ! 2262: ESP = env->sysenter_esp; ! 2263: EIP = env->sysenter_eip; ! 2264: } ! 2265: ! 2266: void helper_sysexit(void) ! 2267: { ! 2268: int cpl; ! 2269: ! 2270: cpl = env->hflags & HF_CPL_MASK; ! 2271: if (env->sysenter_cs == 0 || cpl != 0) { ! 2272: raise_exception_err(EXCP0D_GPF, 0); ! 2273: } ! 2274: cpu_x86_set_cpl(env, 3); ! 2275: cpu_x86_load_seg_cache(env, R_CS, ((env->sysenter_cs + 16) & 0xfffc) | 3, ! 2276: 0, 0xffffffff, ! 2277: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | ! 2278: DESC_S_MASK | (3 << DESC_DPL_SHIFT) | ! 2279: DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); ! 2280: cpu_x86_load_seg_cache(env, R_SS, ((env->sysenter_cs + 24) & 0xfffc) | 3, ! 2281: 0, 0xffffffff, ! 2282: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | ! 2283: DESC_S_MASK | (3 << DESC_DPL_SHIFT) | ! 2284: DESC_W_MASK | DESC_A_MASK); ! 2285: ESP = ECX; ! 2286: EIP = EDX; ! 2287: #ifdef USE_KQEMU ! 2288: if (kqemu_is_ok(env)) { ! 2289: env->exception_index = -1; ! 2290: cpu_loop_exit(); ! 2291: } ! 2292: #endif ! 2293: } ! 2294: ! 2295: void helper_movl_crN_T0(int reg) ! 2296: { ! 2297: #if !defined(CONFIG_USER_ONLY) ! 2298: switch(reg) { ! 2299: case 0: ! 2300: cpu_x86_update_cr0(env, T0); ! 2301: break; ! 2302: case 3: ! 2303: cpu_x86_update_cr3(env, T0); ! 2304: break; ! 2305: case 4: ! 2306: cpu_x86_update_cr4(env, T0); ! 2307: break; ! 2308: case 8: ! 2309: cpu_set_apic_tpr(env, T0); ! 2310: break; ! 2311: default: ! 2312: env->cr[reg] = T0; ! 2313: break; ! 2314: } ! 2315: #endif ! 2316: } ! 2317: ! 2318: /* XXX: do more */ ! 2319: void helper_movl_drN_T0(int reg) ! 2320: { ! 2321: env->dr[reg] = T0; ! 2322: } ! 2323: ! 2324: void helper_invlpg(target_ulong addr) ! 2325: { ! 2326: cpu_x86_flush_tlb(env, addr); ! 2327: } ! 2328: ! 2329: void helper_rdtsc(void) ! 2330: { ! 2331: uint64_t val; ! 2332: ! 2333: if ((env->cr[4] & CR4_TSD_MASK) && ((env->hflags & HF_CPL_MASK) != 0)) { ! 2334: raise_exception(EXCP0D_GPF); ! 2335: } ! 2336: val = cpu_get_tsc(env); ! 2337: EAX = (uint32_t)(val); ! 2338: EDX = (uint32_t)(val >> 32); ! 2339: } ! 2340: ! 2341: #if defined(CONFIG_USER_ONLY) ! 2342: void helper_wrmsr(void) ! 2343: { ! 2344: } ! 2345: ! 2346: void helper_rdmsr(void) ! 2347: { ! 2348: } ! 2349: #else ! 2350: void helper_wrmsr(void) ! 2351: { ! 2352: uint64_t val; ! 2353: ! 2354: val = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32); ! 2355: ! 2356: switch((uint32_t)ECX) { ! 2357: case MSR_IA32_SYSENTER_CS: ! 2358: env->sysenter_cs = val & 0xffff; ! 2359: break; ! 2360: case MSR_IA32_SYSENTER_ESP: ! 2361: env->sysenter_esp = val; ! 2362: break; ! 2363: case MSR_IA32_SYSENTER_EIP: ! 2364: env->sysenter_eip = val; ! 2365: break; ! 2366: case MSR_IA32_APICBASE: ! 2367: cpu_set_apic_base(env, val); ! 2368: break; ! 2369: case MSR_EFER: ! 2370: { ! 2371: uint64_t update_mask; ! 2372: update_mask = 0; ! 2373: if (env->cpuid_ext2_features & CPUID_EXT2_SYSCALL) ! 2374: update_mask |= MSR_EFER_SCE; ! 2375: if (env->cpuid_ext2_features & CPUID_EXT2_LM) ! 2376: update_mask |= MSR_EFER_LME; ! 2377: if (env->cpuid_ext2_features & CPUID_EXT2_FFXSR) ! 2378: update_mask |= MSR_EFER_FFXSR; ! 2379: if (env->cpuid_ext2_features & CPUID_EXT2_NX) ! 2380: update_mask |= MSR_EFER_NXE; ! 2381: env->efer = (env->efer & ~update_mask) | ! 2382: (val & update_mask); ! 2383: } ! 2384: break; ! 2385: case MSR_STAR: ! 2386: env->star = val; ! 2387: break; ! 2388: case MSR_PAT: ! 2389: env->pat = val; ! 2390: break; ! 2391: #ifdef TARGET_X86_64 ! 2392: case MSR_LSTAR: ! 2393: env->lstar = val; ! 2394: break; ! 2395: case MSR_CSTAR: ! 2396: env->cstar = val; ! 2397: break; ! 2398: case MSR_FMASK: ! 2399: env->fmask = val; ! 2400: break; ! 2401: case MSR_FSBASE: ! 2402: env->segs[R_FS].base = val; ! 2403: break; ! 2404: case MSR_GSBASE: ! 2405: env->segs[R_GS].base = val; ! 2406: break; ! 2407: case MSR_KERNELGSBASE: ! 2408: env->kernelgsbase = val; ! 2409: break; ! 2410: #endif ! 2411: default: ! 2412: /* XXX: exception ? */ ! 2413: break; ! 2414: } ! 2415: } ! 2416: ! 2417: void helper_rdmsr(void) ! 2418: { ! 2419: uint64_t val; ! 2420: switch((uint32_t)ECX) { ! 2421: case MSR_IA32_SYSENTER_CS: ! 2422: val = env->sysenter_cs; ! 2423: break; ! 2424: case MSR_IA32_SYSENTER_ESP: ! 2425: val = env->sysenter_esp; ! 2426: break; ! 2427: case MSR_IA32_SYSENTER_EIP: ! 2428: val = env->sysenter_eip; ! 2429: break; ! 2430: case MSR_IA32_APICBASE: ! 2431: val = cpu_get_apic_base(env); ! 2432: break; ! 2433: case MSR_EFER: ! 2434: val = env->efer; ! 2435: break; ! 2436: case MSR_STAR: ! 2437: val = env->star; ! 2438: break; ! 2439: case MSR_PAT: ! 2440: val = env->pat; ! 2441: break; ! 2442: #ifdef TARGET_X86_64 ! 2443: case MSR_LSTAR: ! 2444: val = env->lstar; ! 2445: break; ! 2446: case MSR_CSTAR: ! 2447: val = env->cstar; ! 2448: break; ! 2449: case MSR_FMASK: ! 2450: val = env->fmask; ! 2451: break; ! 2452: case MSR_FSBASE: ! 2453: val = env->segs[R_FS].base; ! 2454: break; ! 2455: case MSR_GSBASE: ! 2456: val = env->segs[R_GS].base; ! 2457: break; ! 2458: case MSR_KERNELGSBASE: ! 2459: val = env->kernelgsbase; ! 2460: break; ! 2461: #endif ! 2462: default: ! 2463: /* XXX: exception ? */ ! 2464: val = 0; ! 2465: break; ! 2466: } ! 2467: EAX = (uint32_t)(val); ! 2468: EDX = (uint32_t)(val >> 32); ! 2469: } ! 2470: #endif ! 2471: ! 2472: void helper_lsl(void) ! 2473: { ! 2474: unsigned int selector, limit; ! 2475: uint32_t e1, e2, eflags; ! 2476: int rpl, dpl, cpl, type; ! 2477: ! 2478: eflags = cc_table[CC_OP].compute_all(); ! 2479: selector = T0 & 0xffff; ! 2480: if (load_segment(&e1, &e2, selector) != 0) ! 2481: goto fail; ! 2482: rpl = selector & 3; ! 2483: dpl = (e2 >> DESC_DPL_SHIFT) & 3; ! 2484: cpl = env->hflags & HF_CPL_MASK; ! 2485: if (e2 & DESC_S_MASK) { ! 2486: if ((e2 & DESC_CS_MASK) && (e2 & DESC_C_MASK)) { ! 2487: /* conforming */ ! 2488: } else { ! 2489: if (dpl < cpl || dpl < rpl) ! 2490: goto fail; ! 2491: } ! 2492: } else { ! 2493: type = (e2 >> DESC_TYPE_SHIFT) & 0xf; ! 2494: switch(type) { ! 2495: case 1: ! 2496: case 2: ! 2497: case 3: ! 2498: case 9: ! 2499: case 11: ! 2500: break; ! 2501: default: ! 2502: goto fail; ! 2503: } ! 2504: if (dpl < cpl || dpl < rpl) { ! 2505: fail: ! 2506: CC_SRC = eflags & ~CC_Z; ! 2507: return; ! 2508: } ! 2509: } ! 2510: limit = get_seg_limit(e1, e2); ! 2511: T1 = limit; ! 2512: CC_SRC = eflags | CC_Z; ! 2513: } ! 2514: ! 2515: void helper_lar(void) ! 2516: { ! 2517: unsigned int selector; ! 2518: uint32_t e1, e2, eflags; ! 2519: int rpl, dpl, cpl, type; ! 2520: ! 2521: eflags = cc_table[CC_OP].compute_all(); ! 2522: selector = T0 & 0xffff; ! 2523: if ((selector & 0xfffc) == 0) ! 2524: goto fail; ! 2525: if (load_segment(&e1, &e2, selector) != 0) ! 2526: goto fail; ! 2527: rpl = selector & 3; ! 2528: dpl = (e2 >> DESC_DPL_SHIFT) & 3; ! 2529: cpl = env->hflags & HF_CPL_MASK; ! 2530: if (e2 & DESC_S_MASK) { ! 2531: if ((e2 & DESC_CS_MASK) && (e2 & DESC_C_MASK)) { ! 2532: /* conforming */ ! 2533: } else { ! 2534: if (dpl < cpl || dpl < rpl) ! 2535: goto fail; ! 2536: } ! 2537: } else { ! 2538: type = (e2 >> DESC_TYPE_SHIFT) & 0xf; ! 2539: switch(type) { ! 2540: case 1: ! 2541: case 2: ! 2542: case 3: ! 2543: case 4: ! 2544: case 5: ! 2545: case 9: ! 2546: case 11: ! 2547: case 12: ! 2548: break; ! 2549: default: ! 2550: goto fail; ! 2551: } ! 2552: if (dpl < cpl || dpl < rpl) { ! 2553: fail: ! 2554: CC_SRC = eflags & ~CC_Z; ! 2555: return; ! 2556: } ! 2557: } ! 2558: T1 = e2 & 0x00f0ff00; ! 2559: CC_SRC = eflags | CC_Z; ! 2560: } ! 2561: ! 2562: void helper_verr(void) ! 2563: { ! 2564: unsigned int selector; ! 2565: uint32_t e1, e2, eflags; ! 2566: int rpl, dpl, cpl; ! 2567: ! 2568: eflags = cc_table[CC_OP].compute_all(); ! 2569: selector = T0 & 0xffff; ! 2570: if ((selector & 0xfffc) == 0) ! 2571: goto fail; ! 2572: if (load_segment(&e1, &e2, selector) != 0) ! 2573: goto fail; ! 2574: if (!(e2 & DESC_S_MASK)) ! 2575: goto fail; ! 2576: rpl = selector & 3; ! 2577: dpl = (e2 >> DESC_DPL_SHIFT) & 3; ! 2578: cpl = env->hflags & HF_CPL_MASK; ! 2579: if (e2 & DESC_CS_MASK) { ! 2580: if (!(e2 & DESC_R_MASK)) ! 2581: goto fail; ! 2582: if (!(e2 & DESC_C_MASK)) { ! 2583: if (dpl < cpl || dpl < rpl) ! 2584: goto fail; ! 2585: } ! 2586: } else { ! 2587: if (dpl < cpl || dpl < rpl) { ! 2588: fail: ! 2589: CC_SRC = eflags & ~CC_Z; ! 2590: return; ! 2591: } ! 2592: } ! 2593: CC_SRC = eflags | CC_Z; ! 2594: } ! 2595: ! 2596: void helper_verw(void) ! 2597: { ! 2598: unsigned int selector; ! 2599: uint32_t e1, e2, eflags; ! 2600: int rpl, dpl, cpl; ! 2601: ! 2602: eflags = cc_table[CC_OP].compute_all(); ! 2603: selector = T0 & 0xffff; ! 2604: if ((selector & 0xfffc) == 0) ! 2605: goto fail; ! 2606: if (load_segment(&e1, &e2, selector) != 0) ! 2607: goto fail; ! 2608: if (!(e2 & DESC_S_MASK)) ! 2609: goto fail; ! 2610: rpl = selector & 3; ! 2611: dpl = (e2 >> DESC_DPL_SHIFT) & 3; ! 2612: cpl = env->hflags & HF_CPL_MASK; ! 2613: if (e2 & DESC_CS_MASK) { ! 2614: goto fail; ! 2615: } else { ! 2616: if (dpl < cpl || dpl < rpl) ! 2617: goto fail; ! 2618: if (!(e2 & DESC_W_MASK)) { ! 2619: fail: ! 2620: CC_SRC = eflags & ~CC_Z; ! 2621: return; ! 2622: } ! 2623: } ! 2624: CC_SRC = eflags | CC_Z; ! 2625: } ! 2626: ! 2627: /* FPU helpers */ ! 2628: ! 2629: void helper_fldt_ST0_A0(void) ! 2630: { ! 2631: int new_fpstt; ! 2632: new_fpstt = (env->fpstt - 1) & 7; ! 2633: env->fpregs[new_fpstt].d = helper_fldt(A0); ! 2634: env->fpstt = new_fpstt; ! 2635: env->fptags[new_fpstt] = 0; /* validate stack entry */ ! 2636: } ! 2637: ! 2638: void helper_fstt_ST0_A0(void) ! 2639: { ! 2640: helper_fstt(ST0, A0); ! 2641: } ! 2642: ! 2643: void fpu_set_exception(int mask) ! 2644: { ! 2645: env->fpus |= mask; ! 2646: if (env->fpus & (~env->fpuc & FPUC_EM)) ! 2647: env->fpus |= FPUS_SE | FPUS_B; ! 2648: } ! 2649: ! 2650: CPU86_LDouble helper_fdiv(CPU86_LDouble a, CPU86_LDouble b) ! 2651: { ! 2652: if (b == 0.0) ! 2653: fpu_set_exception(FPUS_ZE); ! 2654: return a / b; ! 2655: } ! 2656: ! 2657: void fpu_raise_exception(void) ! 2658: { ! 2659: if (env->cr[0] & CR0_NE_MASK) { ! 2660: raise_exception(EXCP10_COPR); ! 2661: } ! 2662: #if !defined(CONFIG_USER_ONLY) ! 2663: else { ! 2664: cpu_set_ferr(env); ! 2665: } ! 2666: #endif ! 2667: } ! 2668: ! 2669: /* BCD ops */ ! 2670: ! 2671: void helper_fbld_ST0_A0(void) ! 2672: { ! 2673: CPU86_LDouble tmp; ! 2674: uint64_t val; ! 2675: unsigned int v; ! 2676: int i; ! 2677: ! 2678: val = 0; ! 2679: for(i = 8; i >= 0; i--) { ! 2680: v = ldub(A0 + i); ! 2681: val = (val * 100) + ((v >> 4) * 10) + (v & 0xf); ! 2682: } ! 2683: tmp = val; ! 2684: if (ldub(A0 + 9) & 0x80) ! 2685: tmp = -tmp; ! 2686: fpush(); ! 2687: ST0 = tmp; ! 2688: } ! 2689: ! 2690: void helper_fbst_ST0_A0(void) ! 2691: { ! 2692: int v; ! 2693: target_ulong mem_ref, mem_end; ! 2694: int64_t val; ! 2695: ! 2696: val = floatx_to_int64(ST0, &env->fp_status); ! 2697: mem_ref = A0; ! 2698: mem_end = mem_ref + 9; ! 2699: if (val < 0) { ! 2700: stb(mem_end, 0x80); ! 2701: val = -val; ! 2702: } else { ! 2703: stb(mem_end, 0x00); ! 2704: } ! 2705: while (mem_ref < mem_end) { ! 2706: if (val == 0) ! 2707: break; ! 2708: v = val % 100; ! 2709: val = val / 100; ! 2710: v = ((v / 10) << 4) | (v % 10); ! 2711: stb(mem_ref++, v); ! 2712: } ! 2713: while (mem_ref < mem_end) { ! 2714: stb(mem_ref++, 0); ! 2715: } ! 2716: } ! 2717: ! 2718: void helper_f2xm1(void) ! 2719: { ! 2720: ST0 = pow(2.0,ST0) - 1.0; ! 2721: } ! 2722: ! 2723: void helper_fyl2x(void) ! 2724: { ! 2725: CPU86_LDouble fptemp; ! 2726: ! 2727: fptemp = ST0; ! 2728: if (fptemp>0.0){ ! 2729: fptemp = log(fptemp)/log(2.0); /* log2(ST) */ ! 2730: ST1 *= fptemp; ! 2731: fpop(); ! 2732: } else { ! 2733: env->fpus &= (~0x4700); ! 2734: env->fpus |= 0x400; ! 2735: } ! 2736: } ! 2737: ! 2738: void helper_fptan(void) ! 2739: { ! 2740: CPU86_LDouble fptemp; ! 2741: ! 2742: fptemp = ST0; ! 2743: if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { ! 2744: env->fpus |= 0x400; ! 2745: } else { ! 2746: ST0 = tan(fptemp); ! 2747: fpush(); ! 2748: ST0 = 1.0; ! 2749: env->fpus &= (~0x400); /* C2 <-- 0 */ ! 2750: /* the above code is for |arg| < 2**52 only */ ! 2751: } ! 2752: } ! 2753: ! 2754: void helper_fpatan(void) ! 2755: { ! 2756: CPU86_LDouble fptemp, fpsrcop; ! 2757: ! 2758: fpsrcop = ST1; ! 2759: fptemp = ST0; ! 2760: ST1 = atan2(fpsrcop,fptemp); ! 2761: fpop(); ! 2762: } ! 2763: ! 2764: void helper_fxtract(void) ! 2765: { ! 2766: CPU86_LDoubleU temp; ! 2767: unsigned int expdif; ! 2768: ! 2769: temp.d = ST0; ! 2770: expdif = EXPD(temp) - EXPBIAS; ! 2771: /*DP exponent bias*/ ! 2772: ST0 = expdif; ! 2773: fpush(); ! 2774: BIASEXPONENT(temp); ! 2775: ST0 = temp.d; ! 2776: } ! 2777: ! 2778: void helper_fprem1(void) ! 2779: { ! 2780: CPU86_LDouble dblq, fpsrcop, fptemp; ! 2781: CPU86_LDoubleU fpsrcop1, fptemp1; ! 2782: int expdif; ! 2783: int q; ! 2784: ! 2785: fpsrcop = ST0; ! 2786: fptemp = ST1; ! 2787: fpsrcop1.d = fpsrcop; ! 2788: fptemp1.d = fptemp; ! 2789: expdif = EXPD(fpsrcop1) - EXPD(fptemp1); ! 2790: if (expdif < 53) { ! 2791: dblq = fpsrcop / fptemp; ! 2792: dblq = (dblq < 0.0)? ceil(dblq): floor(dblq); ! 2793: ST0 = fpsrcop - fptemp*dblq; ! 2794: q = (int)dblq; /* cutting off top bits is assumed here */ ! 2795: env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ ! 2796: /* (C0,C1,C3) <-- (q2,q1,q0) */ ! 2797: env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */ ! 2798: env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */ ! 2799: env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */ ! 2800: } else { ! 2801: env->fpus |= 0x400; /* C2 <-- 1 */ ! 2802: fptemp = pow(2.0, expdif-50); ! 2803: fpsrcop = (ST0 / ST1) / fptemp; ! 2804: /* fpsrcop = integer obtained by rounding to the nearest */ ! 2805: fpsrcop = (fpsrcop-floor(fpsrcop) < ceil(fpsrcop)-fpsrcop)? ! 2806: floor(fpsrcop): ceil(fpsrcop); ! 2807: ST0 -= (ST1 * fpsrcop * fptemp); ! 2808: } ! 2809: } ! 2810: ! 2811: void helper_fprem(void) ! 2812: { ! 2813: CPU86_LDouble dblq, fpsrcop, fptemp; ! 2814: CPU86_LDoubleU fpsrcop1, fptemp1; ! 2815: int expdif; ! 2816: int q; ! 2817: ! 2818: fpsrcop = ST0; ! 2819: fptemp = ST1; ! 2820: fpsrcop1.d = fpsrcop; ! 2821: fptemp1.d = fptemp; ! 2822: expdif = EXPD(fpsrcop1) - EXPD(fptemp1); ! 2823: if ( expdif < 53 ) { ! 2824: dblq = fpsrcop / fptemp; ! 2825: dblq = (dblq < 0.0)? ceil(dblq): floor(dblq); ! 2826: ST0 = fpsrcop - fptemp*dblq; ! 2827: q = (int)dblq; /* cutting off top bits is assumed here */ ! 2828: env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ ! 2829: /* (C0,C1,C3) <-- (q2,q1,q0) */ ! 2830: env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */ ! 2831: env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */ ! 2832: env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */ ! 2833: } else { ! 2834: env->fpus |= 0x400; /* C2 <-- 1 */ ! 2835: fptemp = pow(2.0, expdif-50); ! 2836: fpsrcop = (ST0 / ST1) / fptemp; ! 2837: /* fpsrcop = integer obtained by chopping */ ! 2838: fpsrcop = (fpsrcop < 0.0)? ! 2839: -(floor(fabs(fpsrcop))): floor(fpsrcop); ! 2840: ST0 -= (ST1 * fpsrcop * fptemp); ! 2841: } ! 2842: } ! 2843: ! 2844: void helper_fyl2xp1(void) ! 2845: { ! 2846: CPU86_LDouble fptemp; ! 2847: ! 2848: fptemp = ST0; ! 2849: if ((fptemp+1.0)>0.0) { ! 2850: fptemp = log(fptemp+1.0) / log(2.0); /* log2(ST+1.0) */ ! 2851: ST1 *= fptemp; ! 2852: fpop(); ! 2853: } else { ! 2854: env->fpus &= (~0x4700); ! 2855: env->fpus |= 0x400; ! 2856: } ! 2857: } ! 2858: ! 2859: void helper_fsqrt(void) ! 2860: { ! 2861: CPU86_LDouble fptemp; ! 2862: ! 2863: fptemp = ST0; ! 2864: if (fptemp<0.0) { ! 2865: env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ ! 2866: env->fpus |= 0x400; ! 2867: } ! 2868: ST0 = sqrt(fptemp); ! 2869: } ! 2870: ! 2871: void helper_fsincos(void) ! 2872: { ! 2873: CPU86_LDouble fptemp; ! 2874: ! 2875: fptemp = ST0; ! 2876: if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { ! 2877: env->fpus |= 0x400; ! 2878: } else { ! 2879: ST0 = sin(fptemp); ! 2880: fpush(); ! 2881: ST0 = cos(fptemp); ! 2882: env->fpus &= (~0x400); /* C2 <-- 0 */ ! 2883: /* the above code is for |arg| < 2**63 only */ ! 2884: } ! 2885: } ! 2886: ! 2887: void helper_frndint(void) ! 2888: { ! 2889: ST0 = floatx_round_to_int(ST0, &env->fp_status); ! 2890: } ! 2891: ! 2892: void helper_fscale(void) ! 2893: { ! 2894: ST0 = ldexp (ST0, (int)(ST1)); ! 2895: } ! 2896: ! 2897: void helper_fsin(void) ! 2898: { ! 2899: CPU86_LDouble fptemp; ! 2900: ! 2901: fptemp = ST0; ! 2902: if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { ! 2903: env->fpus |= 0x400; ! 2904: } else { ! 2905: ST0 = sin(fptemp); ! 2906: env->fpus &= (~0x400); /* C2 <-- 0 */ ! 2907: /* the above code is for |arg| < 2**53 only */ ! 2908: } ! 2909: } ! 2910: ! 2911: void helper_fcos(void) ! 2912: { ! 2913: CPU86_LDouble fptemp; ! 2914: ! 2915: fptemp = ST0; ! 2916: if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { ! 2917: env->fpus |= 0x400; ! 2918: } else { ! 2919: ST0 = cos(fptemp); ! 2920: env->fpus &= (~0x400); /* C2 <-- 0 */ ! 2921: /* the above code is for |arg5 < 2**63 only */ ! 2922: } ! 2923: } ! 2924: ! 2925: void helper_fxam_ST0(void) ! 2926: { ! 2927: CPU86_LDoubleU temp; ! 2928: int expdif; ! 2929: ! 2930: temp.d = ST0; ! 2931: ! 2932: env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ ! 2933: if (SIGND(temp)) ! 2934: env->fpus |= 0x200; /* C1 <-- 1 */ ! 2935: ! 2936: expdif = EXPD(temp); ! 2937: if (expdif == MAXEXPD) { ! 2938: if (MANTD(temp) == 0) ! 2939: env->fpus |= 0x500 /*Infinity*/; ! 2940: else ! 2941: env->fpus |= 0x100 /*NaN*/; ! 2942: } else if (expdif == 0) { ! 2943: if (MANTD(temp) == 0) ! 2944: env->fpus |= 0x4000 /*Zero*/; ! 2945: else ! 2946: env->fpus |= 0x4400 /*Denormal*/; ! 2947: } else { ! 2948: env->fpus |= 0x400; ! 2949: } ! 2950: } ! 2951: ! 2952: void helper_fstenv(target_ulong ptr, int data32) ! 2953: { ! 2954: int fpus, fptag, exp, i; ! 2955: uint64_t mant; ! 2956: CPU86_LDoubleU tmp; ! 2957: ! 2958: fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; ! 2959: fptag = 0; ! 2960: for (i=7; i>=0; i--) { ! 2961: fptag <<= 2; ! 2962: if (env->fptags[i]) { ! 2963: fptag |= 3; ! 2964: } else { ! 2965: tmp.d = env->fpregs[i].d; ! 2966: exp = EXPD(tmp); ! 2967: mant = MANTD(tmp); ! 2968: if (exp == 0 && mant == 0) { ! 2969: /* zero */ ! 2970: fptag |= 1; ! 2971: } else if (exp == 0 || exp == MAXEXPD ! 2972: #ifdef USE_X86LDOUBLE ! 2973: || (mant & (1LL << 63)) == 0 ! 2974: #endif ! 2975: ) { ! 2976: /* NaNs, infinity, denormal */ ! 2977: fptag |= 2; ! 2978: } ! 2979: } ! 2980: } ! 2981: if (data32) { ! 2982: /* 32 bit */ ! 2983: stl(ptr, env->fpuc); ! 2984: stl(ptr + 4, fpus); ! 2985: stl(ptr + 8, fptag); ! 2986: stl(ptr + 12, 0); /* fpip */ ! 2987: stl(ptr + 16, 0); /* fpcs */ ! 2988: stl(ptr + 20, 0); /* fpoo */ ! 2989: stl(ptr + 24, 0); /* fpos */ ! 2990: } else { ! 2991: /* 16 bit */ ! 2992: stw(ptr, env->fpuc); ! 2993: stw(ptr + 2, fpus); ! 2994: stw(ptr + 4, fptag); ! 2995: stw(ptr + 6, 0); ! 2996: stw(ptr + 8, 0); ! 2997: stw(ptr + 10, 0); ! 2998: stw(ptr + 12, 0); ! 2999: } ! 3000: } ! 3001: ! 3002: void helper_fldenv(target_ulong ptr, int data32) ! 3003: { ! 3004: int i, fpus, fptag; ! 3005: ! 3006: if (data32) { ! 3007: env->fpuc = lduw(ptr); ! 3008: fpus = lduw(ptr + 4); ! 3009: fptag = lduw(ptr + 8); ! 3010: } ! 3011: else { ! 3012: env->fpuc = lduw(ptr); ! 3013: fpus = lduw(ptr + 2); ! 3014: fptag = lduw(ptr + 4); ! 3015: } ! 3016: env->fpstt = (fpus >> 11) & 7; ! 3017: env->fpus = fpus & ~0x3800; ! 3018: for(i = 0;i < 8; i++) { ! 3019: env->fptags[i] = ((fptag & 3) == 3); ! 3020: fptag >>= 2; ! 3021: } ! 3022: } ! 3023: ! 3024: void helper_fsave(target_ulong ptr, int data32) ! 3025: { ! 3026: CPU86_LDouble tmp; ! 3027: int i; ! 3028: ! 3029: helper_fstenv(ptr, data32); ! 3030: ! 3031: ptr += (14 << data32); ! 3032: for(i = 0;i < 8; i++) { ! 3033: tmp = ST(i); ! 3034: helper_fstt(tmp, ptr); ! 3035: ptr += 10; ! 3036: } ! 3037: ! 3038: /* fninit */ ! 3039: env->fpus = 0; ! 3040: env->fpstt = 0; ! 3041: env->fpuc = 0x37f; ! 3042: env->fptags[0] = 1; ! 3043: env->fptags[1] = 1; ! 3044: env->fptags[2] = 1; ! 3045: env->fptags[3] = 1; ! 3046: env->fptags[4] = 1; ! 3047: env->fptags[5] = 1; ! 3048: env->fptags[6] = 1; ! 3049: env->fptags[7] = 1; ! 3050: } ! 3051: ! 3052: void helper_frstor(target_ulong ptr, int data32) ! 3053: { ! 3054: CPU86_LDouble tmp; ! 3055: int i; ! 3056: ! 3057: helper_fldenv(ptr, data32); ! 3058: ptr += (14 << data32); ! 3059: ! 3060: for(i = 0;i < 8; i++) { ! 3061: tmp = helper_fldt(ptr); ! 3062: ST(i) = tmp; ! 3063: ptr += 10; ! 3064: } ! 3065: } ! 3066: ! 3067: void helper_fxsave(target_ulong ptr, int data64) ! 3068: { ! 3069: int fpus, fptag, i, nb_xmm_regs; ! 3070: CPU86_LDouble tmp; ! 3071: target_ulong addr; ! 3072: ! 3073: fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; ! 3074: fptag = 0; ! 3075: for(i = 0; i < 8; i++) { ! 3076: fptag |= (env->fptags[i] << i); ! 3077: } ! 3078: stw(ptr, env->fpuc); ! 3079: stw(ptr + 2, fpus); ! 3080: stw(ptr + 4, fptag ^ 0xff); ! 3081: ! 3082: addr = ptr + 0x20; ! 3083: for(i = 0;i < 8; i++) { ! 3084: tmp = ST(i); ! 3085: helper_fstt(tmp, addr); ! 3086: addr += 16; ! 3087: } ! 3088: ! 3089: if (env->cr[4] & CR4_OSFXSR_MASK) { ! 3090: /* XXX: finish it */ ! 3091: stl(ptr + 0x18, env->mxcsr); /* mxcsr */ ! 3092: stl(ptr + 0x1c, 0x0000ffff); /* mxcsr_mask */ ! 3093: nb_xmm_regs = 8 << data64; ! 3094: addr = ptr + 0xa0; ! 3095: for(i = 0; i < nb_xmm_regs; i++) { ! 3096: stq(addr, env->xmm_regs[i].XMM_Q(0)); ! 3097: stq(addr + 8, env->xmm_regs[i].XMM_Q(1)); ! 3098: addr += 16; ! 3099: } ! 3100: } ! 3101: } ! 3102: ! 3103: void helper_fxrstor(target_ulong ptr, int data64) ! 3104: { ! 3105: int i, fpus, fptag, nb_xmm_regs; ! 3106: CPU86_LDouble tmp; ! 3107: target_ulong addr; ! 3108: ! 3109: env->fpuc = lduw(ptr); ! 3110: fpus = lduw(ptr + 2); ! 3111: fptag = lduw(ptr + 4); ! 3112: env->fpstt = (fpus >> 11) & 7; ! 3113: env->fpus = fpus & ~0x3800; ! 3114: fptag ^= 0xff; ! 3115: for(i = 0;i < 8; i++) { ! 3116: env->fptags[i] = ((fptag >> i) & 1); ! 3117: } ! 3118: ! 3119: addr = ptr + 0x20; ! 3120: for(i = 0;i < 8; i++) { ! 3121: tmp = helper_fldt(addr); ! 3122: ST(i) = tmp; ! 3123: addr += 16; ! 3124: } ! 3125: ! 3126: if (env->cr[4] & CR4_OSFXSR_MASK) { ! 3127: /* XXX: finish it */ ! 3128: env->mxcsr = ldl(ptr + 0x18); ! 3129: //ldl(ptr + 0x1c); ! 3130: nb_xmm_regs = 8 << data64; ! 3131: addr = ptr + 0xa0; ! 3132: for(i = 0; i < nb_xmm_regs; i++) { ! 3133: env->xmm_regs[i].XMM_Q(0) = ldq(addr); ! 3134: env->xmm_regs[i].XMM_Q(1) = ldq(addr + 8); ! 3135: addr += 16; ! 3136: } ! 3137: } ! 3138: } ! 3139: ! 3140: #ifndef USE_X86LDOUBLE ! 3141: ! 3142: void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, CPU86_LDouble f) ! 3143: { ! 3144: CPU86_LDoubleU temp; ! 3145: int e; ! 3146: ! 3147: temp.d = f; ! 3148: /* mantissa */ ! 3149: *pmant = (MANTD(temp) << 11) | (1LL << 63); ! 3150: /* exponent + sign */ ! 3151: e = EXPD(temp) - EXPBIAS + 16383; ! 3152: e |= SIGND(temp) >> 16; ! 3153: *pexp = e; ! 3154: } ! 3155: ! 3156: CPU86_LDouble cpu_set_fp80(uint64_t mant, uint16_t upper) ! 3157: { ! 3158: CPU86_LDoubleU temp; ! 3159: int e; ! 3160: uint64_t ll; ! 3161: ! 3162: /* XXX: handle overflow ? */ ! 3163: e = (upper & 0x7fff) - 16383 + EXPBIAS; /* exponent */ ! 3164: e |= (upper >> 4) & 0x800; /* sign */ ! 3165: ll = (mant >> 11) & ((1LL << 52) - 1); ! 3166: #ifdef __arm__ ! 3167: temp.l.upper = (e << 20) | (ll >> 32); ! 3168: temp.l.lower = ll; ! 3169: #else ! 3170: temp.ll = ll | ((uint64_t)e << 52); ! 3171: #endif ! 3172: return temp.d; ! 3173: } ! 3174: ! 3175: #else ! 3176: ! 3177: void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, CPU86_LDouble f) ! 3178: { ! 3179: CPU86_LDoubleU temp; ! 3180: ! 3181: temp.d = f; ! 3182: *pmant = temp.l.lower; ! 3183: *pexp = temp.l.upper; ! 3184: } ! 3185: ! 3186: CPU86_LDouble cpu_set_fp80(uint64_t mant, uint16_t upper) ! 3187: { ! 3188: CPU86_LDoubleU temp; ! 3189: ! 3190: temp.l.upper = upper; ! 3191: temp.l.lower = mant; ! 3192: return temp.d; ! 3193: } ! 3194: #endif ! 3195: ! 3196: #ifdef TARGET_X86_64 ! 3197: ! 3198: //#define DEBUG_MULDIV ! 3199: ! 3200: static void add128(uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b) ! 3201: { ! 3202: *plow += a; ! 3203: /* carry test */ ! 3204: if (*plow < a) ! 3205: (*phigh)++; ! 3206: *phigh += b; ! 3207: } ! 3208: ! 3209: static void neg128(uint64_t *plow, uint64_t *phigh) ! 3210: { ! 3211: *plow = ~ *plow; ! 3212: *phigh = ~ *phigh; ! 3213: add128(plow, phigh, 1, 0); ! 3214: } ! 3215: ! 3216: static void mul64(uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b) ! 3217: { ! 3218: uint32_t a0, a1, b0, b1; ! 3219: uint64_t v; ! 3220: ! 3221: a0 = a; ! 3222: a1 = a >> 32; ! 3223: ! 3224: b0 = b; ! 3225: b1 = b >> 32; ! 3226: ! 3227: v = (uint64_t)a0 * (uint64_t)b0; ! 3228: *plow = v; ! 3229: *phigh = 0; ! 3230: ! 3231: v = (uint64_t)a0 * (uint64_t)b1; ! 3232: add128(plow, phigh, v << 32, v >> 32); ! 3233: ! 3234: v = (uint64_t)a1 * (uint64_t)b0; ! 3235: add128(plow, phigh, v << 32, v >> 32); ! 3236: ! 3237: v = (uint64_t)a1 * (uint64_t)b1; ! 3238: *phigh += v; ! 3239: #ifdef DEBUG_MULDIV ! 3240: printf("mul: 0x%016llx * 0x%016llx = 0x%016llx%016llx\n", ! 3241: a, b, *phigh, *plow); ! 3242: #endif ! 3243: } ! 3244: ! 3245: static void imul64(uint64_t *plow, uint64_t *phigh, int64_t a, int64_t b) ! 3246: { ! 3247: int sa, sb; ! 3248: sa = (a < 0); ! 3249: if (sa) ! 3250: a = -a; ! 3251: sb = (b < 0); ! 3252: if (sb) ! 3253: b = -b; ! 3254: mul64(plow, phigh, a, b); ! 3255: if (sa ^ sb) { ! 3256: neg128(plow, phigh); ! 3257: } ! 3258: } ! 3259: ! 3260: /* return TRUE if overflow */ ! 3261: static int div64(uint64_t *plow, uint64_t *phigh, uint64_t b) ! 3262: { ! 3263: uint64_t q, r, a1, a0; ! 3264: int i, qb; ! 3265: ! 3266: a0 = *plow; ! 3267: a1 = *phigh; ! 3268: if (a1 == 0) { ! 3269: q = a0 / b; ! 3270: r = a0 % b; ! 3271: *plow = q; ! 3272: *phigh = r; ! 3273: } else { ! 3274: if (a1 >= b) ! 3275: return 1; ! 3276: /* XXX: use a better algorithm */ ! 3277: for(i = 0; i < 64; i++) { ! 3278: a1 = (a1 << 1) | (a0 >> 63); ! 3279: if (a1 >= b) { ! 3280: a1 -= b; ! 3281: qb = 1; ! 3282: } else { ! 3283: qb = 0; ! 3284: } ! 3285: a0 = (a0 << 1) | qb; ! 3286: } ! 3287: #if defined(DEBUG_MULDIV) ! 3288: printf("div: 0x%016llx%016llx / 0x%016llx: q=0x%016llx r=0x%016llx\n", ! 3289: *phigh, *plow, b, a0, a1); ! 3290: #endif ! 3291: *plow = a0; ! 3292: *phigh = a1; ! 3293: } ! 3294: return 0; ! 3295: } ! 3296: ! 3297: /* return TRUE if overflow */ ! 3298: static int idiv64(uint64_t *plow, uint64_t *phigh, int64_t b) ! 3299: { ! 3300: int sa, sb; ! 3301: sa = ((int64_t)*phigh < 0); ! 3302: if (sa) ! 3303: neg128(plow, phigh); ! 3304: sb = (b < 0); ! 3305: if (sb) ! 3306: b = -b; ! 3307: if (div64(plow, phigh, b) != 0) ! 3308: return 1; ! 3309: if (sa ^ sb) { ! 3310: if (*plow > (1ULL << 63)) ! 3311: return 1; ! 3312: *plow = - *plow; ! 3313: } else { ! 3314: if (*plow >= (1ULL << 63)) ! 3315: return 1; ! 3316: } ! 3317: if (sa) ! 3318: *phigh = - *phigh; ! 3319: return 0; ! 3320: } ! 3321: ! 3322: void helper_mulq_EAX_T0(void) ! 3323: { ! 3324: uint64_t r0, r1; ! 3325: ! 3326: mul64(&r0, &r1, EAX, T0); ! 3327: EAX = r0; ! 3328: EDX = r1; ! 3329: CC_DST = r0; ! 3330: CC_SRC = r1; ! 3331: } ! 3332: ! 3333: void helper_imulq_EAX_T0(void) ! 3334: { ! 3335: uint64_t r0, r1; ! 3336: ! 3337: imul64(&r0, &r1, EAX, T0); ! 3338: EAX = r0; ! 3339: EDX = r1; ! 3340: CC_DST = r0; ! 3341: CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63)); ! 3342: } ! 3343: ! 3344: void helper_imulq_T0_T1(void) ! 3345: { ! 3346: uint64_t r0, r1; ! 3347: ! 3348: imul64(&r0, &r1, T0, T1); ! 3349: T0 = r0; ! 3350: CC_DST = r0; ! 3351: CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63)); ! 3352: } ! 3353: ! 3354: void helper_divq_EAX_T0(void) ! 3355: { ! 3356: uint64_t r0, r1; ! 3357: if (T0 == 0) { ! 3358: raise_exception(EXCP00_DIVZ); ! 3359: } ! 3360: r0 = EAX; ! 3361: r1 = EDX; ! 3362: if (div64(&r0, &r1, T0)) ! 3363: raise_exception(EXCP00_DIVZ); ! 3364: EAX = r0; ! 3365: EDX = r1; ! 3366: } ! 3367: ! 3368: void helper_idivq_EAX_T0(void) ! 3369: { ! 3370: uint64_t r0, r1; ! 3371: if (T0 == 0) { ! 3372: raise_exception(EXCP00_DIVZ); ! 3373: } ! 3374: r0 = EAX; ! 3375: r1 = EDX; ! 3376: if (idiv64(&r0, &r1, T0)) ! 3377: raise_exception(EXCP00_DIVZ); ! 3378: EAX = r0; ! 3379: EDX = r1; ! 3380: } ! 3381: ! 3382: #endif ! 3383: ! 3384: float approx_rsqrt(float a) ! 3385: { ! 3386: return 1.0 / sqrt(a); ! 3387: } ! 3388: ! 3389: float approx_rcp(float a) ! 3390: { ! 3391: return 1.0 / a; ! 3392: } ! 3393: ! 3394: void update_fp_status(void) ! 3395: { ! 3396: int rnd_type; ! 3397: ! 3398: /* set rounding mode */ ! 3399: switch(env->fpuc & RC_MASK) { ! 3400: default: ! 3401: case RC_NEAR: ! 3402: rnd_type = float_round_nearest_even; ! 3403: break; ! 3404: case RC_DOWN: ! 3405: rnd_type = float_round_down; ! 3406: break; ! 3407: case RC_UP: ! 3408: rnd_type = float_round_up; ! 3409: break; ! 3410: case RC_CHOP: ! 3411: rnd_type = float_round_to_zero; ! 3412: break; ! 3413: } ! 3414: set_float_rounding_mode(rnd_type, &env->fp_status); ! 3415: #ifdef FLOATX80 ! 3416: switch((env->fpuc >> 8) & 3) { ! 3417: case 0: ! 3418: rnd_type = 32; ! 3419: break; ! 3420: case 2: ! 3421: rnd_type = 64; ! 3422: break; ! 3423: case 3: ! 3424: default: ! 3425: rnd_type = 80; ! 3426: break; ! 3427: } ! 3428: set_floatx80_rounding_precision(rnd_type, &env->fp_status); ! 3429: #endif ! 3430: } ! 3431: ! 3432: #if !defined(CONFIG_USER_ONLY) ! 3433: ! 3434: #define MMUSUFFIX _mmu ! 3435: #define GETPC() (__builtin_return_address(0)) ! 3436: ! 3437: #define SHIFT 0 ! 3438: #include "softmmu_template.h" ! 3439: ! 3440: #define SHIFT 1 ! 3441: #include "softmmu_template.h" ! 3442: ! 3443: #define SHIFT 2 ! 3444: #include "softmmu_template.h" ! 3445: ! 3446: #define SHIFT 3 ! 3447: #include "softmmu_template.h" ! 3448: ! 3449: #endif ! 3450: ! 3451: /* try to fill the TLB and return an exception if error. If retaddr is ! 3452: NULL, it means that the function was called in C code (i.e. not ! 3453: from generated code or from helper.c) */ ! 3454: /* XXX: fix it to restore all registers */ ! 3455: void tlb_fill(target_ulong addr, int is_write, int is_user, void *retaddr) ! 3456: { ! 3457: TranslationBlock *tb; ! 3458: int ret; ! 3459: unsigned long pc; ! 3460: CPUX86State *saved_env; ! 3461: ! 3462: /* XXX: hack to restore env in all cases, even if not called from ! 3463: generated code */ ! 3464: saved_env = env; ! 3465: env = cpu_single_env; ! 3466: ! 3467: ret = cpu_x86_handle_mmu_fault(env, addr, is_write, is_user, 1); ! 3468: if (ret) { ! 3469: if (retaddr) { ! 3470: /* now we have a real cpu fault */ ! 3471: pc = (unsigned long)retaddr; ! 3472: tb = tb_find_pc(pc); ! 3473: if (tb) { ! 3474: /* the PC is inside the translated code. It means that we have ! 3475: a virtual CPU fault */ ! 3476: cpu_restore_state(tb, env, pc, NULL); ! 3477: } ! 3478: } ! 3479: if (retaddr) ! 3480: raise_exception_err(EXCP0E_PAGE, env->error_code); ! 3481: else ! 3482: raise_exception_err_norestore(EXCP0E_PAGE, env->error_code); ! 3483: } ! 3484: env = saved_env; ! 3485: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.