Annotation of qemu/target-i386/helper.c, revision 1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.