int kqemu_cpu_exec(CPUState *env)

{

    struct kqemu_cpu_state kcpu_state, *kenv = &kcpu_state;

    int ret, cpl, i;

#ifdef CONFIG_PROFILER

    int64_t ti;

#endif

#ifdef _WIN32

    DWORD temp;

#endif



#ifdef CONFIG_PROFILER

    ti = profile_getclock();

#endif

    LOG_INT("kqemu: cpu_exec: enter\n");

    LOG_INT_STATE(env);

    for(i = 0; i < CPU_NB_REGS; i++)

        kenv->regs[i] = env->regs[i];

    kenv->eip = env->eip;

    kenv->eflags = env->eflags;

    for(i = 0; i < 6; i++)

        kqemu_load_seg(&kenv->segs[i], &env->segs[i]);

    kqemu_load_seg(&kenv->ldt, &env->ldt);

    kqemu_load_seg(&kenv->tr, &env->tr);

    kqemu_load_seg(&kenv->gdt, &env->gdt);

    kqemu_load_seg(&kenv->idt, &env->idt);

    kenv->cr0 = env->cr[0];

    kenv->cr2 = env->cr[2];

    kenv->cr3 = env->cr[3];

    kenv->cr4 = env->cr[4];

    kenv->a20_mask = env->a20_mask;

    kenv->efer = env->efer;

    kenv->tsc_offset = 0;

    kenv->star = env->star;

    kenv->sysenter_cs = env->sysenter_cs;

    kenv->sysenter_esp = env->sysenter_esp;

    kenv->sysenter_eip = env->sysenter_eip;

#ifdef TARGET_X86_64

    kenv->lstar = env->lstar;

    kenv->cstar = env->cstar;

    kenv->fmask = env->fmask;

    kenv->kernelgsbase = env->kernelgsbase;

#endif

    if (env->dr[7] & 0xff) {

        kenv->dr7 = env->dr[7];

        kenv->dr0 = env->dr[0];

        kenv->dr1 = env->dr[1];

        kenv->dr2 = env->dr[2];

        kenv->dr3 = env->dr[3];

    } else {

        kenv->dr7 = 0;

    }

    kenv->dr6 = env->dr[6];

    cpl = (env->hflags & HF_CPL_MASK);

    kenv->cpl = cpl;

    kenv->nb_pages_to_flush = nb_pages_to_flush;

    kenv->user_only = (env->kqemu_enabled == 1);

    kenv->nb_ram_pages_to_update = nb_ram_pages_to_update;

    nb_ram_pages_to_update = 0;

    kenv->nb_modified_ram_pages = nb_modified_ram_pages;



    kqemu_reset_modified_ram_pages();



    if (env->cpuid_features & CPUID_FXSR)

        restore_native_fp_fxrstor(env);

    else

        restore_native_fp_frstor(env);



#ifdef _WIN32

    if (DeviceIoControl(kqemu_fd, KQEMU_EXEC,

                        kenv, sizeof(struct kqemu_cpu_state),

                        kenv, sizeof(struct kqemu_cpu_state),

                        &temp, NULL)) {

        ret = kenv->retval;

    } else {

        ret = -1;

    }

#else

    ioctl(kqemu_fd, KQEMU_EXEC, kenv);

    ret = kenv->retval;

#endif

    if (env->cpuid_features & CPUID_FXSR)

        save_native_fp_fxsave(env);

    else

        save_native_fp_fsave(env);



    for(i = 0; i < CPU_NB_REGS; i++)

        env->regs[i] = kenv->regs[i];

    env->eip = kenv->eip;

    env->eflags = kenv->eflags;

    for(i = 0; i < 6; i++)

        kqemu_save_seg(&env->segs[i], &kenv->segs[i]);

    cpu_x86_set_cpl(env, kenv->cpl);

    kqemu_save_seg(&env->ldt, &kenv->ldt);

    env->cr[0] = kenv->cr0;

    env->cr[4] = kenv->cr4;

    env->cr[3] = kenv->cr3;

    env->cr[2] = kenv->cr2;

    env->dr[6] = kenv->dr6;

#ifdef TARGET_X86_64

    env->kernelgsbase = kenv->kernelgsbase;

#endif



    

    if (kenv->nb_pages_to_flush >= KQEMU_FLUSH_ALL) {

        tlb_flush(env, 1);

    } else {

        for(i = 0; i < kenv->nb_pages_to_flush; i++) {

            tlb_flush_page(env, pages_to_flush[i]);

        }

    }

    nb_pages_to_flush = 0;



#ifdef CONFIG_PROFILER

    kqemu_time += profile_getclock() - ti;

    kqemu_exec_count++;

#endif



    if (kenv->nb_ram_pages_to_update > 0) {

        cpu_tlb_update_dirty(env);

    }



    if (kenv->nb_modified_ram_pages > 0) {

        for(i = 0; i < kenv->nb_modified_ram_pages; i++) {

            unsigned long addr;

            addr = modified_ram_pages[i];

            tb_invalidate_phys_page_range(addr, addr + TARGET_PAGE_SIZE, 0);

        }

    }



    

    {

        unsigned int new_hflags;

#ifdef TARGET_X86_64

        if ((env->hflags & HF_LMA_MASK) &&

            (env->segs[R_CS].flags & DESC_L_MASK)) {

            

            new_hflags = HF_CS32_MASK | HF_SS32_MASK | HF_CS64_MASK;

        } else

#endif

        {

            

            new_hflags = (env->segs[R_CS].flags & DESC_B_MASK)

                >> (DESC_B_SHIFT - HF_CS32_SHIFT);

            new_hflags |= (env->segs[R_SS].flags & DESC_B_MASK)

                >> (DESC_B_SHIFT - HF_SS32_SHIFT);

            if (!(env->cr[0] & CR0_PE_MASK) ||

                   (env->eflags & VM_MASK) ||

                   !(env->hflags & HF_CS32_MASK)) {

                









                new_hflags |= HF_ADDSEG_MASK;

            } else {

                new_hflags |= ((env->segs[R_DS].base |

                                env->segs[R_ES].base |

                                env->segs[R_SS].base) != 0) <<

                    HF_ADDSEG_SHIFT;

            }

        }

        env->hflags = (env->hflags &

           ~(HF_CS32_MASK | HF_SS32_MASK | HF_CS64_MASK | HF_ADDSEG_MASK)) |

            new_hflags;

    }

    

    env->hflags = (env->hflags & ~(HF_MP_MASK | HF_EM_MASK | HF_TS_MASK)) |

        ((env->cr[0] << (HF_MP_SHIFT - 1)) & (HF_MP_MASK | HF_EM_MASK | HF_TS_MASK));

    if (env->cr[4] & CR4_OSFXSR_MASK)

        env->hflags |= HF_OSFXSR_MASK;

    else

        env->hflags &= ~HF_OSFXSR_MASK;



    LOG_INT("kqemu: kqemu_cpu_exec: ret=0x%x\n", ret);

    if (ret == KQEMU_RET_SYSCALL) {

        

        return do_syscall(env, kenv);

    } else

    if ((ret & 0xff00) == KQEMU_RET_INT) {

        env->exception_index = ret & 0xff;

        env->error_code = 0;

        env->exception_is_int = 1;

        env->exception_next_eip = kenv->next_eip;

#ifdef CONFIG_PROFILER

        kqemu_ret_int_count++;

#endif

        LOG_INT("kqemu: interrupt v=%02x:\n", env->exception_index);

        LOG_INT_STATE(env);

        return 1;

    } else if ((ret & 0xff00) == KQEMU_RET_EXCEPTION) {

        env->exception_index = ret & 0xff;

        env->error_code = kenv->error_code;

        env->exception_is_int = 0;

        env->exception_next_eip = 0;

#ifdef CONFIG_PROFILER

        kqemu_ret_excp_count++;

#endif

        LOG_INT("kqemu: exception v=%02x e=%04x:\n",

                    env->exception_index, env->error_code);

        LOG_INT_STATE(env);

        return 1;

    } else if (ret == KQEMU_RET_INTR) {

#ifdef CONFIG_PROFILER

        kqemu_ret_intr_count++;

#endif

        LOG_INT_STATE(env);

        return 0;

    } else if (ret == KQEMU_RET_SOFTMMU) {

#ifdef CONFIG_PROFILER

        {

            unsigned long pc = env->eip + env->segs[R_CS].base;

            kqemu_record_pc(pc);

        }

#endif

        LOG_INT_STATE(env);

        return 2;

    } else {

        cpu_dump_state(env, stderr, fprintf, 0);

        fprintf(stderr, "Unsupported return value: 0x%x\n", ret);

        exit(1);

    }

    return 0;

}
