Commit 023fe10d24acd124d0b7c5c5ac8edd41d6cc08f2

Authored by bellard
1 parent f66723fa

fnop FPU exception support (aka FreeBSD FPU probe) - sysenter/sysexit support (u…

…ntested, not enabled in cpuid)


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@869 c046a42c-6fe2-441c-8c8c-71466251a162
target-i386/exec.h
@@ -167,6 +167,8 @@ void helper_divl_EAX_T0(uint32_t eip); @@ -167,6 +167,8 @@ void helper_divl_EAX_T0(uint32_t eip);
167 void helper_idivl_EAX_T0(uint32_t eip); 167 void helper_idivl_EAX_T0(uint32_t eip);
168 void helper_cmpxchg8b(void); 168 void helper_cmpxchg8b(void);
169 void helper_cpuid(void); 169 void helper_cpuid(void);
  170 +void helper_sysenter(void);
  171 +void helper_sysexit(void);
170 void helper_rdtsc(void); 172 void helper_rdtsc(void);
171 void helper_rdmsr(void); 173 void helper_rdmsr(void);
172 void helper_wrmsr(void); 174 void helper_wrmsr(void);
target-i386/helper.c
@@ -1746,6 +1746,50 @@ void helper_lret_protected(int shift, int addend) @@ -1746,6 +1746,50 @@ void helper_lret_protected(int shift, int addend)
1746 helper_ret_protected(shift, 0, addend); 1746 helper_ret_protected(shift, 0, addend);
1747 } 1747 }
1748 1748
  1749 +void helper_sysenter(void)
  1750 +{
  1751 + if (env->sysenter_cs == 0) {
  1752 + raise_exception_err(EXCP0D_GPF, 0);
  1753 + }
  1754 + env->eflags &= ~(VM_MASK | IF_MASK | RF_MASK);
  1755 + cpu_x86_set_cpl(env, 0);
  1756 + cpu_x86_load_seg_cache(env, R_CS, env->sysenter_cs & 0xfffc,
  1757 + NULL, 0xffffffff,
  1758 + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
  1759 + DESC_S_MASK |
  1760 + DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
  1761 + cpu_x86_load_seg_cache(env, R_SS, (env->sysenter_cs + 8) & 0xfffc,
  1762 + NULL, 0xffffffff,
  1763 + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
  1764 + DESC_S_MASK |
  1765 + DESC_W_MASK | DESC_A_MASK);
  1766 + ESP = env->sysenter_esp;
  1767 + EIP = env->sysenter_eip;
  1768 +}
  1769 +
  1770 +void helper_sysexit(void)
  1771 +{
  1772 + int cpl;
  1773 +
  1774 + cpl = env->hflags & HF_CPL_MASK;
  1775 + if (env->sysenter_cs == 0 || cpl != 0) {
  1776 + raise_exception_err(EXCP0D_GPF, 0);
  1777 + }
  1778 + cpu_x86_set_cpl(env, 3);
  1779 + cpu_x86_load_seg_cache(env, R_CS, ((env->sysenter_cs + 16) & 0xfffc) | 3,
  1780 + NULL, 0xffffffff,
  1781 + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
  1782 + DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
  1783 + DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
  1784 + cpu_x86_load_seg_cache(env, R_SS, ((env->sysenter_cs + 24) & 0xfffc) | 3,
  1785 + NULL, 0xffffffff,
  1786 + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
  1787 + DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
  1788 + DESC_W_MASK | DESC_A_MASK);
  1789 + ESP = ECX;
  1790 + EIP = EDX;
  1791 +}
  1792 +
1749 void helper_movl_crN_T0(int reg) 1793 void helper_movl_crN_T0(int reg)
1750 { 1794 {
1751 switch(reg) { 1795 switch(reg) {
target-i386/op.c
@@ -700,6 +700,16 @@ void OPPROTO op_cpuid(void) @@ -700,6 +700,16 @@ void OPPROTO op_cpuid(void)
700 helper_cpuid(); 700 helper_cpuid();
701 } 701 }
702 702
  703 +void OPPROTO op_sysenter(void)
  704 +{
  705 + helper_sysenter();
  706 +}
  707 +
  708 +void OPPROTO op_sysexit(void)
  709 +{
  710 + helper_sysexit();
  711 +}
  712 +
703 void OPPROTO op_rdmsr(void) 713 void OPPROTO op_rdmsr(void)
704 { 714 {
705 helper_rdmsr(); 715 helper_rdmsr();
target-i386/translate.c
@@ -2973,6 +2973,11 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) @@ -2973,6 +2973,11 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
2973 case 0x0a: /* grp d9/2 */ 2973 case 0x0a: /* grp d9/2 */
2974 switch(rm) { 2974 switch(rm) {
2975 case 0: /* fnop */ 2975 case 0: /* fnop */
  2976 + /* check exceptions (FreeBSD FPU probe) */
  2977 + if (s->cc_op != CC_OP_DYNAMIC)
  2978 + gen_op_set_cc_op(s->cc_op);
  2979 + gen_op_jmp_im(pc_start - s->cs_base);
  2980 + gen_op_fwait();
2976 break; 2981 break;
2977 default: 2982 default:
2978 goto illegal_op; 2983 goto illegal_op;
@@ -3881,6 +3886,32 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) @@ -3881,6 +3886,32 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
3881 case 0x131: /* rdtsc */ 3886 case 0x131: /* rdtsc */
3882 gen_op_rdtsc(); 3887 gen_op_rdtsc();
3883 break; 3888 break;
  3889 + case 0x134: /* sysenter */
  3890 + if (!s->pe) {
  3891 + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
  3892 + } else {
  3893 + if (s->cc_op != CC_OP_DYNAMIC) {
  3894 + gen_op_set_cc_op(s->cc_op);
  3895 + s->cc_op = CC_OP_DYNAMIC;
  3896 + }
  3897 + gen_op_jmp_im(pc_start - s->cs_base);
  3898 + gen_op_sysenter();
  3899 + gen_eob(s);
  3900 + }
  3901 + break;
  3902 + case 0x135: /* sysexit */
  3903 + if (!s->pe) {
  3904 + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
  3905 + } else {
  3906 + if (s->cc_op != CC_OP_DYNAMIC) {
  3907 + gen_op_set_cc_op(s->cc_op);
  3908 + s->cc_op = CC_OP_DYNAMIC;
  3909 + }
  3910 + gen_op_jmp_im(pc_start - s->cs_base);
  3911 + gen_op_sysexit();
  3912 + gen_eob(s);
  3913 + }
  3914 + break;
3884 case 0x1a2: /* cpuid */ 3915 case 0x1a2: /* cpuid */
3885 gen_op_cpuid(); 3916 gen_op_cpuid();
3886 break; 3917 break;