void helper_lcall_protected_T0_T1(int shift, int next_eip)

{

    int new_cs, new_eip;

    uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count;

    uint32_t ss, ss_e1, ss_e2, push_size, sp, type, ss_dpl;

    uint32_t old_ss, old_esp, val, i, limit;

    uint8_t *ssp, *old_ssp;

    

    new_cs = T0;

    new_eip = T1;

    if ((new_cs & 0xfffc) == 0)

        raise_exception_err(EXCP0D_GPF, 0);

    if (load_segment(&e1, &e2, new_cs) != 0)

        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);

    cpl = env->hflags & HF_CPL_MASK;

    if (e2 & DESC_S_MASK) {

        if (!(e2 & DESC_CS_MASK))

            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);

        dpl = (e2 >> DESC_DPL_SHIFT) & 3;

        if (e2 & DESC_CS_MASK) {

            /* conforming code segment */

            if (dpl > cpl)

                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);

        } else {

            /* non conforming code segment */

            rpl = new_cs & 3;

            if (rpl > cpl)

                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);

            if (dpl != cpl)

                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);

        }

        if (!(e2 & DESC_P_MASK))

            raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);



        sp = ESP;

        if (!(env->segs[R_SS].flags & DESC_B_MASK))

            sp &= 0xffff;

        ssp = env->segs[R_SS].base + sp;

        if (shift) {

            ssp -= 4;

            stl_kernel(ssp, env->segs[R_CS].selector);

            ssp -= 4;

            stl_kernel(ssp, next_eip);

        } else {

            ssp -= 2;

            stw_kernel(ssp, env->segs[R_CS].selector);

            ssp -= 2;

            stw_kernel(ssp, next_eip);

        }

        sp -= (4 << shift);

        

        limit = get_seg_limit(e1, e2);

        if (new_eip > limit)

            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);

        /* from this point, not restartable */

        if (!(env->segs[R_SS].flags & DESC_B_MASK))

            ESP = (ESP & 0xffff0000) | (sp & 0xffff);

        else

            ESP = sp;

        cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,

                       get_seg_base(e1, e2), limit, e2);

        EIP = new_eip;

    } else {

        /* check gate type */

        type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;

        switch(type) {

        case 1: /* available 286 TSS */

        case 9: /* available 386 TSS */

        case 5: /* task gate */

            cpu_abort(env, "task gate not supported");

            break;

        case 4: /* 286 call gate */

        case 12: /* 386 call gate */

            break;

        default:

            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);

            break;

        }

        shift = type >> 3;



        dpl = (e2 >> DESC_DPL_SHIFT) & 3;

        rpl = new_cs & 3;

        if (dpl < cpl || dpl < rpl)

            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);

        /* check valid bit */

        if (!(e2 & DESC_P_MASK))

            raise_exception_err(EXCP0B_NOSEG,  new_cs & 0xfffc);

        selector = e1 >> 16;

        offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff);

        if ((selector & 0xfffc) == 0)

            raise_exception_err(EXCP0D_GPF, 0);



        if (load_segment(&e1, &e2, selector) != 0)

            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);

        if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))

            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);

        dpl = (e2 >> DESC_DPL_SHIFT) & 3;

        if (dpl > cpl)

            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);

        if (!(e2 & DESC_P_MASK))

            raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);



        if (!(e2 & DESC_C_MASK) && dpl < cpl) {

            /* to inner priviledge */

            get_ss_esp_from_tss(&ss, &sp, dpl);

            if ((ss & 0xfffc) == 0)

                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);

            if ((ss & 3) != dpl)

                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);

            if (load_segment(&ss_e1, &ss_e2, ss) != 0)

                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);

            ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;

            if (ss_dpl != dpl)

                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);

            if (!(ss_e2 & DESC_S_MASK) ||

                (ss_e2 & DESC_CS_MASK) ||

                !(ss_e2 & DESC_W_MASK))

                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);

            if (!(ss_e2 & DESC_P_MASK))

                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);

            

            param_count = e2 & 0x1f;

            push_size = ((param_count * 2) + 8) << shift;



            old_esp = ESP;

            old_ss = env->segs[R_SS].selector;

            if (!(env->segs[R_SS].flags & DESC_B_MASK))

                old_esp &= 0xffff;

            old_ssp = env->segs[R_SS].base + old_esp;

            

            /* XXX: from this point not restartable */

            ss = (ss & ~3) | dpl;

            cpu_x86_load_seg_cache(env, R_SS, ss, 

                           get_seg_base(ss_e1, ss_e2),

                           get_seg_limit(ss_e1, ss_e2),

                           ss_e2);



            if (!(env->segs[R_SS].flags & DESC_B_MASK))

                sp &= 0xffff;

            ssp = env->segs[R_SS].base + sp;

            if (shift) {

                ssp -= 4;

                stl_kernel(ssp, old_ss);

                ssp -= 4;

                stl_kernel(ssp, old_esp);

                ssp -= 4 * param_count;

                for(i = 0; i < param_count; i++) {

                    val = ldl_kernel(old_ssp + i * 4);

                    stl_kernel(ssp + i * 4, val);

                }

            } else {

                ssp -= 2;

                stw_kernel(ssp, old_ss);

                ssp -= 2;

                stw_kernel(ssp, old_esp);

                ssp -= 2 * param_count;

                for(i = 0; i < param_count; i++) {

                    val = lduw_kernel(old_ssp + i * 2);

                    stw_kernel(ssp + i * 2, val);

                }

            }

        } else {

            /* to same priviledge */

            if (!(env->segs[R_SS].flags & DESC_B_MASK))

                sp &= 0xffff;

            ssp = env->segs[R_SS].base + sp;

            push_size = (4 << shift);

        }



        if (shift) {

            ssp -= 4;

            stl_kernel(ssp, env->segs[R_CS].selector);

            ssp -= 4;

            stl_kernel(ssp, next_eip);

        } else {

            ssp -= 2;

            stw_kernel(ssp, env->segs[R_CS].selector);

            ssp -= 2;

            stw_kernel(ssp, next_eip);

        }



        sp -= push_size;

        selector = (selector & ~3) | dpl;

        cpu_x86_load_seg_cache(env, R_CS, selector, 

                       get_seg_base(e1, e2),

                       get_seg_limit(e1, e2),

                       e2);

        cpu_x86_set_cpl(env, dpl);

        

        /* from this point, not restartable if same priviledge */

        if (!(env->segs[R_SS].flags & DESC_B_MASK))

            ESP = (ESP & 0xffff0000) | (sp & 0xffff);

        else

            ESP = sp;

        EIP = offset;

    }

}

void helper_lcall_protected_T0_T1(int shift, int next_eip)

{

    int new_cs, new_eip;

    uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count;

    uint32_t ss, ss_e1, ss_e2, push_size, sp, type, ss_dpl;

    uint32_t old_ss, old_esp, val, i, limit;

    uint8_t *ssp, *old_ssp;

    

    new_cs = T0;

    new_eip = T1;

    if ((new_cs & 0xfffc) == 0)

        raise_exception_err(EXCP0D_GPF, 0);

    if (load_segment(&e1, &e2, new_cs) != 0)

        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);

    cpl = env->hflags & HF_CPL_MASK;

    if (e2 & DESC_S_MASK) {

        if (!(e2 & DESC_CS_MASK))

            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);

        dpl = (e2 >> DESC_DPL_SHIFT) & 3;

        if (e2 & DESC_CS_MASK) {

            

            if (dpl > cpl)

                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);

        } else {

            

            rpl = new_cs & 3;

            if (rpl > cpl)

                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);

            if (dpl != cpl)

                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);

        }

        if (!(e2 & DESC_P_MASK))

            raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);



        sp = ESP;

        if (!(env->segs[R_SS].flags & DESC_B_MASK))

            sp &= 0xffff;

        ssp = env->segs[R_SS].base + sp;

        if (shift) {

            ssp -= 4;

            stl_kernel(ssp, env->segs[R_CS].selector);

            ssp -= 4;

            stl_kernel(ssp, next_eip);

        } else {

            ssp -= 2;

            stw_kernel(ssp, env->segs[R_CS].selector);

            ssp -= 2;

            stw_kernel(ssp, next_eip);

        }

        sp -= (4 << shift);

        

        limit = get_seg_limit(e1, e2);

        if (new_eip > limit)

            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);

        

        if (!(env->segs[R_SS].flags & DESC_B_MASK))

            ESP = (ESP & 0xffff0000) | (sp & 0xffff);

        else

            ESP = sp;

        cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,

                       get_seg_base(e1, e2), limit, e2);

        EIP = new_eip;

    } else {

        

        type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;

        switch(type) {

        case 1: 

        case 9: 

        case 5: 

            cpu_abort(env, "task gate not supported");

            break;

        case 4: 

        case 12: 

            break;

        default:

            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);

            break;

        }

        shift = type >> 3;



        dpl = (e2 >> DESC_DPL_SHIFT) & 3;

        rpl = new_cs & 3;

        if (dpl < cpl || dpl < rpl)

            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);

        

        if (!(e2 & DESC_P_MASK))

            raise_exception_err(EXCP0B_NOSEG,  new_cs & 0xfffc);

        selector = e1 >> 16;

        offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff);

        if ((selector & 0xfffc) == 0)

            raise_exception_err(EXCP0D_GPF, 0);



        if (load_segment(&e1, &e2, selector) != 0)

            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);

        if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))

            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);

        dpl = (e2 >> DESC_DPL_SHIFT) & 3;

        if (dpl > cpl)

            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);

        if (!(e2 & DESC_P_MASK))

            raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);



        if (!(e2 & DESC_C_MASK) && dpl < cpl) {

            

            get_ss_esp_from_tss(&ss, &sp, dpl);

            if ((ss & 0xfffc) == 0)

                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);

            if ((ss & 3) != dpl)

                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);

            if (load_segment(&ss_e1, &ss_e2, ss) != 0)

                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);

            ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;

            if (ss_dpl != dpl)

                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);

            if (!(ss_e2 & DESC_S_MASK) ||

                (ss_e2 & DESC_CS_MASK) ||

                !(ss_e2 & DESC_W_MASK))

                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);

            if (!(ss_e2 & DESC_P_MASK))

                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);

            

            param_count = e2 & 0x1f;

            push_size = ((param_count * 2) + 8) << shift;



            old_esp = ESP;

            old_ss = env->segs[R_SS].selector;

            if (!(env->segs[R_SS].flags & DESC_B_MASK))

                old_esp &= 0xffff;

            old_ssp = env->segs[R_SS].base + old_esp;

            

            

            ss = (ss & ~3) | dpl;

            cpu_x86_load_seg_cache(env, R_SS, ss, 

                           get_seg_base(ss_e1, ss_e2),

                           get_seg_limit(ss_e1, ss_e2),

                           ss_e2);



            if (!(env->segs[R_SS].flags & DESC_B_MASK))

                sp &= 0xffff;

            ssp = env->segs[R_SS].base + sp;

            if (shift) {

                ssp -= 4;

                stl_kernel(ssp, old_ss);

                ssp -= 4;

                stl_kernel(ssp, old_esp);

                ssp -= 4 * param_count;

                for(i = 0; i < param_count; i++) {

                    val = ldl_kernel(old_ssp + i * 4);

                    stl_kernel(ssp + i * 4, val);

                }

            } else {

                ssp -= 2;

                stw_kernel(ssp, old_ss);

                ssp -= 2;

                stw_kernel(ssp, old_esp);

                ssp -= 2 * param_count;

                for(i = 0; i < param_count; i++) {

                    val = lduw_kernel(old_ssp + i * 2);

                    stw_kernel(ssp + i * 2, val);

                }

            }

        } else {

            

            if (!(env->segs[R_SS].flags & DESC_B_MASK))

                sp &= 0xffff;

            ssp = env->segs[R_SS].base + sp;

            push_size = (4 << shift);

        }



        if (shift) {

            ssp -= 4;

            stl_kernel(ssp, env->segs[R_CS].selector);

            ssp -= 4;

            stl_kernel(ssp, next_eip);

        } else {

            ssp -= 2;

            stw_kernel(ssp, env->segs[R_CS].selector);

            ssp -= 2;

            stw_kernel(ssp, next_eip);

        }



        sp -= push_size;

        selector = (selector & ~3) | dpl;

        cpu_x86_load_seg_cache(env, R_CS, selector, 

                       get_seg_base(e1, e2),

                       get_seg_limit(e1, e2),

                       e2);

        cpu_x86_set_cpl(env, dpl);

        

        

        if (!(env->segs[R_SS].flags & DESC_B_MASK))

            ESP = (ESP & 0xffff0000) | (sp & 0xffff);

        else

            ESP = sp;

        EIP = offset;

    }

}

void FUNC_0(int VAR_0, int VAR_1)

{

    int VAR_2, VAR_3;

    uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count;

    uint32_t ss, ss_e1, ss_e2, push_size, sp, type, ss_dpl;

    uint32_t old_ss, old_esp, val, i, limit;

    uint8_t *ssp, *old_ssp;

    

    VAR_2 = T0;

    VAR_3 = T1;

    if ((VAR_2 & 0xfffc) == 0)

        raise_exception_err(EXCP0D_GPF, 0);

    if (load_segment(&e1, &e2, VAR_2) != 0)

        raise_exception_err(EXCP0D_GPF, VAR_2 & 0xfffc);

    cpl = env->hflags & HF_CPL_MASK;

    if (e2 & DESC_S_MASK) {

        if (!(e2 & DESC_CS_MASK))

            raise_exception_err(EXCP0D_GPF, VAR_2 & 0xfffc);

        dpl = (e2 >> DESC_DPL_SHIFT) & 3;

        if (e2 & DESC_CS_MASK) {

            

            if (dpl > cpl)

                raise_exception_err(EXCP0D_GPF, VAR_2 & 0xfffc);

        } else {

            

            rpl = VAR_2 & 3;

            if (rpl > cpl)

                raise_exception_err(EXCP0D_GPF, VAR_2 & 0xfffc);

            if (dpl != cpl)

                raise_exception_err(EXCP0D_GPF, VAR_2 & 0xfffc);

        }

        if (!(e2 & DESC_P_MASK))

            raise_exception_err(EXCP0B_NOSEG, VAR_2 & 0xfffc);



        sp = ESP;

        if (!(env->segs[R_SS].flags & DESC_B_MASK))

            sp &= 0xffff;

        ssp = env->segs[R_SS].base + sp;

        if (VAR_0) {

            ssp -= 4;

            stl_kernel(ssp, env->segs[R_CS].selector);

            ssp -= 4;

            stl_kernel(ssp, VAR_1);

        } else {

            ssp -= 2;

            stw_kernel(ssp, env->segs[R_CS].selector);

            ssp -= 2;

            stw_kernel(ssp, VAR_1);

        }

        sp -= (4 << VAR_0);

        

        limit = get_seg_limit(e1, e2);

        if (VAR_3 > limit)

            raise_exception_err(EXCP0D_GPF, VAR_2 & 0xfffc);

        

        if (!(env->segs[R_SS].flags & DESC_B_MASK))

            ESP = (ESP & 0xffff0000) | (sp & 0xffff);

        else

            ESP = sp;

        cpu_x86_load_seg_cache(env, R_CS, (VAR_2 & 0xfffc) | cpl,

                       get_seg_base(e1, e2), limit, e2);

        EIP = VAR_3;

    } else {

        

        type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;

        switch(type) {

        case 1: 

        case 9: 

        case 5: 

            cpu_abort(env, "task gate not supported");

            break;

        case 4: 

        case 12: 

            break;

        default:

            raise_exception_err(EXCP0D_GPF, VAR_2 & 0xfffc);

            break;

        }

        VAR_0 = type >> 3;



        dpl = (e2 >> DESC_DPL_SHIFT) & 3;

        rpl = VAR_2 & 3;

        if (dpl < cpl || dpl < rpl)

            raise_exception_err(EXCP0D_GPF, VAR_2 & 0xfffc);

        

        if (!(e2 & DESC_P_MASK))

            raise_exception_err(EXCP0B_NOSEG,  VAR_2 & 0xfffc);

        selector = e1 >> 16;

        offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff);

        if ((selector & 0xfffc) == 0)

            raise_exception_err(EXCP0D_GPF, 0);



        if (load_segment(&e1, &e2, selector) != 0)

            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);

        if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))

            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);

        dpl = (e2 >> DESC_DPL_SHIFT) & 3;

        if (dpl > cpl)

            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);

        if (!(e2 & DESC_P_MASK))

            raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);



        if (!(e2 & DESC_C_MASK) && dpl < cpl) {

            

            get_ss_esp_from_tss(&ss, &sp, dpl);

            if ((ss & 0xfffc) == 0)

                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);

            if ((ss & 3) != dpl)

                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);

            if (load_segment(&ss_e1, &ss_e2, ss) != 0)

                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);

            ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;

            if (ss_dpl != dpl)

                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);

            if (!(ss_e2 & DESC_S_MASK) ||

                (ss_e2 & DESC_CS_MASK) ||

                !(ss_e2 & DESC_W_MASK))

                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);

            if (!(ss_e2 & DESC_P_MASK))

                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);

            

            param_count = e2 & 0x1f;

            push_size = ((param_count * 2) + 8) << VAR_0;



            old_esp = ESP;

            old_ss = env->segs[R_SS].selector;

            if (!(env->segs[R_SS].flags & DESC_B_MASK))

                old_esp &= 0xffff;

            old_ssp = env->segs[R_SS].base + old_esp;

            

            

            ss = (ss & ~3) | dpl;

            cpu_x86_load_seg_cache(env, R_SS, ss, 

                           get_seg_base(ss_e1, ss_e2),

                           get_seg_limit(ss_e1, ss_e2),

                           ss_e2);



            if (!(env->segs[R_SS].flags & DESC_B_MASK))

                sp &= 0xffff;

            ssp = env->segs[R_SS].base + sp;

            if (VAR_0) {

                ssp -= 4;

                stl_kernel(ssp, old_ss);

                ssp -= 4;

                stl_kernel(ssp, old_esp);

                ssp -= 4 * param_count;

                for(i = 0; i < param_count; i++) {

                    val = ldl_kernel(old_ssp + i * 4);

                    stl_kernel(ssp + i * 4, val);

                }

            } else {

                ssp -= 2;

                stw_kernel(ssp, old_ss);

                ssp -= 2;

                stw_kernel(ssp, old_esp);

                ssp -= 2 * param_count;

                for(i = 0; i < param_count; i++) {

                    val = lduw_kernel(old_ssp + i * 2);

                    stw_kernel(ssp + i * 2, val);

                }

            }

        } else {

            

            if (!(env->segs[R_SS].flags & DESC_B_MASK))

                sp &= 0xffff;

            ssp = env->segs[R_SS].base + sp;

            push_size = (4 << VAR_0);

        }



        if (VAR_0) {

            ssp -= 4;

            stl_kernel(ssp, env->segs[R_CS].selector);

            ssp -= 4;

            stl_kernel(ssp, VAR_1);

        } else {

            ssp -= 2;

            stw_kernel(ssp, env->segs[R_CS].selector);

            ssp -= 2;

            stw_kernel(ssp, VAR_1);

        }



        sp -= push_size;

        selector = (selector & ~3) | dpl;

        cpu_x86_load_seg_cache(env, R_CS, selector, 

                       get_seg_base(e1, e2),

                       get_seg_limit(e1, e2),

                       e2);

        cpu_x86_set_cpl(env, dpl);

        

        

        if (!(env->segs[R_SS].flags & DESC_B_MASK))

            ESP = (ESP & 0xffff0000) | (sp & 0xffff);

        else

            ESP = sp;

        EIP = offset;

    }

}

void FUNC_0(int VAR_0, int VAR_1)
{ int VAR_2, VAR_3; uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count; uint32_t ss, ss_e1, ss_e2, push_size, sp, type, ss_dpl; uint32_t old_ss, old_esp, val, i, limit; uint8_t *ssp, *old_ssp; VAR_2 = T0; VAR_3 = T1; if ((VAR_2 & 0xfffc) == 0)
raise_exception_err(EXCP0D_GPF, 0); if (load_segment(&e1, &e2, VAR_2) != 0)
raise_exception_err(EXCP0D_GPF, VAR_2 & 0xfffc); cpl = env->hflags & HF_CPL_MASK; if (e2 & DESC_S_MASK) { if (!(e2 & DESC_CS_MASK))
raise_exception_err(EXCP0D_GPF, VAR_2 & 0xfffc); dpl = (e2 >> DESC_DPL_SHIFT) & 3; if (e2 & DESC_CS_MASK) { if (dpl > cpl)
raise_exception_err(EXCP0D_GPF, VAR_2 & 0xfffc); } else { rpl = VAR_2 & 3; if (rpl > cpl)
raise_exception_err(EXCP0D_GPF, VAR_2 & 0xfffc); if (dpl != cpl)
raise_exception_err(EXCP0D_GPF, VAR_2 & 0xfffc); } if (!(e2 & DESC_P_MASK))
raise_exception_err(EXCP0B_NOSEG, VAR_2 & 0xfffc); sp = ESP; if (!(env->segs[R_SS].flags & DESC_B_MASK))
sp &= 0xffff; ssp = env->segs[R_SS].base + sp; if (VAR_0) { ssp -= 4; stl_kernel(ssp, env->segs[R_CS].selector); ssp -= 4; stl_kernel(ssp, VAR_1); } else { ssp -= 2; stw_kernel(ssp, env->segs[R_CS].selector); ssp -= 2; stw_kernel(ssp, VAR_1); } sp -= (4 << VAR_0); limit = get_seg_limit(e1, e2); if (VAR_3 > limit)
raise_exception_err(EXCP0D_GPF, VAR_2 & 0xfffc); if (!(env->segs[R_SS].flags & DESC_B_MASK))
ESP = (ESP & 0xffff0000) | (sp & 0xffff); else
ESP = sp; cpu_x86_load_seg_cache(env, R_CS, (VAR_2 & 0xfffc) | cpl,
get_seg_base(e1, e2), limit, e2); EIP = VAR_3; } else { type = (e2 >> DESC_TYPE_SHIFT) & 0x1f; switch(type) { case 1:
case 9:
case 5:
cpu_abort(env, "task gate not supported"); break; case 4:
case 12:
break; default:
raise_exception_err(EXCP0D_GPF, VAR_2 & 0xfffc); break; } VAR_0 = type >> 3; dpl = (e2 >> DESC_DPL_SHIFT) & 3; rpl = VAR_2 & 3; if (dpl < cpl || dpl < rpl)
raise_exception_err(EXCP0D_GPF, VAR_2 & 0xfffc); if (!(e2 & DESC_P_MASK))
raise_exception_err(EXCP0B_NOSEG,  VAR_2 & 0xfffc); selector = e1 >> 16; offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff); if ((selector & 0xfffc) == 0)
raise_exception_err(EXCP0D_GPF, 0); if (load_segment(&e1, &e2, selector) != 0)
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); dpl = (e2 >> DESC_DPL_SHIFT) & 3; if (dpl > cpl)
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); if (!(e2 & DESC_P_MASK))
raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); if (!(e2 & DESC_C_MASK) && dpl < cpl) { get_ss_esp_from_tss(&ss, &sp, dpl); if ((ss & 0xfffc) == 0)
raise_exception_err(EXCP0A_TSS, ss & 0xfffc); if ((ss & 3) != dpl)
raise_exception_err(EXCP0A_TSS, ss & 0xfffc); if (load_segment(&ss_e1, &ss_e2, ss) != 0)
raise_exception_err(EXCP0A_TSS, ss & 0xfffc); ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3; if (ss_dpl != dpl)
raise_exception_err(EXCP0A_TSS, ss & 0xfffc); if (!(ss_e2 & DESC_S_MASK) ||
(ss_e2 & DESC_CS_MASK) ||
!(ss_e2 & DESC_W_MASK))
raise_exception_err(EXCP0A_TSS, ss & 0xfffc); if (!(ss_e2 & DESC_P_MASK))
raise_exception_err(EXCP0A_TSS, ss & 0xfffc); param_count = e2 & 0x1f; push_size = ((param_count * 2) + 8) << VAR_0; old_esp = ESP; old_ss = env->segs[R_SS].selector; if (!(env->segs[R_SS].flags & DESC_B_MASK))
old_esp &= 0xffff; old_ssp = env->segs[R_SS].base + old_esp; ss = (ss & ~3) | dpl; cpu_x86_load_seg_cache(env, R_SS, ss,
get_seg_base(ss_e1, ss_e2),
get_seg_limit(ss_e1, ss_e2),
ss_e2); if (!(env->segs[R_SS].flags & DESC_B_MASK))
sp &= 0xffff; ssp = env->segs[R_SS].base + sp; if (VAR_0) { ssp -= 4; stl_kernel(ssp, old_ss); ssp -= 4; stl_kernel(ssp, old_esp); ssp -= 4 * param_count; for(i = 0; i < param_count; i++) { val = ldl_kernel(old_ssp + i * 4); stl_kernel(ssp + i * 4, val); } } else { ssp -= 2; stw_kernel(ssp, old_ss); ssp -= 2; stw_kernel(ssp, old_esp); ssp -= 2 * param_count; for(i = 0; i < param_count; i++) { val = lduw_kernel(old_ssp + i * 2); stw_kernel(ssp + i * 2, val); } } } else { if (!(env->segs[R_SS].flags & DESC_B_MASK))
sp &= 0xffff; ssp = env->segs[R_SS].base + sp; push_size = (4 << VAR_0); } if (VAR_0) { ssp -= 4; stl_kernel(ssp, env->segs[R_CS].selector); ssp -= 4; stl_kernel(ssp, VAR_1); } else { ssp -= 2; stw_kernel(ssp, env->segs[R_CS].selector); ssp -= 2; stw_kernel(ssp, VAR_1); } sp -= push_size; selector = (selector & ~3) | dpl; cpu_x86_load_seg_cache(env, R_CS, selector,
get_seg_base(e1, e2),
get_seg_limit(e1, e2),
e2); cpu_x86_set_cpl(env, dpl); if (!(env->segs[R_SS].flags & DESC_B_MASK))
ESP = (ESP & 0xffff0000) | (sp & 0xffff); else
ESP = sp; EIP = offset; } }