VirtualBox

Changeset 94162 in vbox for trunk/src/VBox/VMM/VMMAll


Ignore:
Timestamp:
Mar 10, 2022 10:29:05 PM (3 years ago)
Author:
vboxsync
Message:

VMM/IEM: Try deal with basic Intel/AMD EFLAGS difference for double shifts (intel side tests). bugref:9898

Location:
trunk/src/VBox/VMM/VMMAll
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/VMMAll/IEMAll.cpp

    r94156 r94162  
    11351135
    11361136
    1137 /** Function table for the SHLD instruction */
     1137/** Function table for the SHLD instruction. */
    11381138IEM_STATIC const IEMOPSHIFTDBLSIZES g_iemAImpl_shld =
    11391139{
     
    11431143};
    11441144
    1145 /** Function table for the SHRD instruction */
     1145/** Function table for the SHLD instruction, AMD EFLAGS variation. */
     1146IEM_STATIC const IEMOPSHIFTDBLSIZES g_iemAImpl_shld_amd =
     1147{
     1148    iemAImpl_shld_u16_amd,
     1149    iemAImpl_shld_u32_amd,
     1150    iemAImpl_shld_u64_amd
     1151};
     1152
     1153/** Function table for the SHLD instruction, Intel EFLAGS variation. */
     1154IEM_STATIC const IEMOPSHIFTDBLSIZES g_iemAImpl_shld_intel =
     1155{
     1156    iemAImpl_shld_u16_intel,
     1157    iemAImpl_shld_u32_intel,
     1158    iemAImpl_shld_u64_intel
     1159};
     1160
     1161/** EFLAGS variation selection table for the SHLD instruction. */
     1162IEM_STATIC const IEMOPSHIFTDBLSIZES * const g_iemAImpl_shld_eflags[] =
     1163{
     1164    &g_iemAImpl_shld,
     1165    &g_iemAImpl_shld_intel,
     1166    &g_iemAImpl_shld_amd,
     1167    &g_iemAImpl_shld
     1168};
     1169
     1170/** Function table for the SHRD instruction. */
    11461171IEM_STATIC const IEMOPSHIFTDBLSIZES g_iemAImpl_shrd =
    11471172{
    11481173    iemAImpl_shrd_u16,
    11491174    iemAImpl_shrd_u32,
    1150     iemAImpl_shrd_u64,
     1175    iemAImpl_shrd_u64
     1176};
     1177
     1178/** Function table for the SHRD instruction, AMD EFLAGS variation. */
     1179IEM_STATIC const IEMOPSHIFTDBLSIZES g_iemAImpl_shrd_amd =
     1180{
     1181    iemAImpl_shrd_u16_amd,
     1182    iemAImpl_shrd_u32_amd,
     1183    iemAImpl_shrd_u64_amd
     1184};
     1185
     1186/** Function table for the SHRD instruction, Intel EFLAGS variation. */
     1187IEM_STATIC const IEMOPSHIFTDBLSIZES g_iemAImpl_shrd_intel =
     1188{
     1189    iemAImpl_shrd_u16_intel,
     1190    iemAImpl_shrd_u32_intel,
     1191    iemAImpl_shrd_u64_intel
     1192};
     1193
     1194/** EFLAGS variation selection table for the SHRD instruction. */
     1195IEM_STATIC const IEMOPSHIFTDBLSIZES * const g_iemAImpl_shrd_eflags[] =
     1196{
     1197    &g_iemAImpl_shrd,
     1198    &g_iemAImpl_shrd_intel,
     1199    &g_iemAImpl_shrd_amd,
     1200    &g_iemAImpl_shrd
    11511201};
    11521202
  • trunk/src/VBox/VMM/VMMAll/IEMAllAImpl.asm

    r94156 r94162  
    14131413%macro IEMIMPL_SHIFT_DBL_OP 3
    14141414BEGINCODE
     1415BEGINPROC_FASTCALL iemAImpl_ %+ %1 %+ _u16_intel, 16
     1416BEGINPROC_FASTCALL iemAImpl_ %+ %1 %+ _u16_amd, 16
    14151417BEGINPROC_FASTCALL iemAImpl_ %+ %1 %+ _u16, 16
    14161418        PROLOGUE_4_ARGS
     
    14281430ENDPROC iemAImpl_ %+ %1 %+ _u16
    14291431
     1432BEGINPROC_FASTCALL iemAImpl_ %+ %1 %+ _u32_intel, 16
     1433BEGINPROC_FASTCALL iemAImpl_ %+ %1 %+ _u32_amd, 16
    14301434BEGINPROC_FASTCALL iemAImpl_ %+ %1 %+ _u32, 16
    14311435        PROLOGUE_4_ARGS
     
    14441448
    14451449 %ifdef RT_ARCH_AMD64
     1450BEGINPROC_FASTCALL iemAImpl_ %+ %1 %+ _u64_intel, 20
     1451BEGINPROC_FASTCALL iemAImpl_ %+ %1 %+ _u64_amd, 20
    14461452BEGINPROC_FASTCALL iemAImpl_ %+ %1 %+ _u64, 20
    14471453        PROLOGUE_4_ARGS
  • trunk/src/VBox/VMM/VMMAll/IEMAllAImplC.cpp

    r94156 r94162  
    26782678/*
    26792679 * SHLD
     2680 *
     2681 *  - CF is the last bit shifted out of puDst.
     2682 *  - AF is always cleared by Intel 10980XE.
     2683 *  - AF is always set by AMD 3990X.
     2684 *  - OF is set according to the first shift on Intel 10980XE, it seems.
     2685 *  - OF is set according to the last sub-shift on AMD 3990X.
     2686 *  - ZF, SF and PF are calculated according to the result by both vendors.
    26802687 */
    26812688#define EMIT_SHLD(a_cBitsWidth) \
     
    26832690                                                         uint ## a_cBitsWidth ## _t uSrc, uint8_t cShift, uint32_t *pfEFlags)) \
    26842691{ \
     2692    /** @todo this ain't right for 16-bit. Apparently it should use 0x1f instead \
     2693     *        of 0xf for masking and use uSrc in repetitive fashion...  */ \
    26852694    cShift &= a_cBitsWidth - 1; \
    26862695    if (cShift) \
    26872696    { \
    2688         uint ## a_cBitsWidth ## _t const uDst = *puDst; \
     2697        uint ## a_cBitsWidth ## _t const uDst    = *puDst; \
    26892698        uint ## a_cBitsWidth ## _t       uResult = uDst << cShift; \
    26902699        uResult |= uSrc >> (a_cBitsWidth - cShift); \
    26912700        *puDst = uResult; \
    26922701        \
    2693         /* Calc EFLAGS.  CF is the last bit shifted out of puDst. The OF flag \
    2694            indicates a sign change for a single shift, whereas intel documents \
    2695            setting it to zero for higher shift counts and AMD just says it's \
    2696            undefined, however AMD x3990 sets it according to the last sub-shift. \
    2697            On AMD x3990 the AF flag is always set. */ \
    26982702        uint32_t fEfl = *pfEFlags & ~X86_EFL_STATUS_BITS; \
    2699         if (true /*AMD*/) \
    2700         { \
    2701             fEfl |= X86_EFL_GET_OF_ ## a_cBitsWidth((uDst << (cShift - 1)) ^ uResult); /* Set according to last shift. */ \
    2702             fEfl |= X86_EFL_AF; \
    2703         } \
    2704         else \
    2705         { \
    2706             if (cShift == 1) \
    2707                 fEfl |= X86_EFL_GET_OF_ ## a_cBitsWidth((uDst ^ uResult)); \
    2708             fEfl |= X86_EFL_AF; /* ? */ \
    2709         } \
     2703        AssertCompile(X86_EFL_CF_BIT == 0); \
     2704        fEfl |= X86_EFL_GET_OF_ ## a_cBitsWidth(uDst ^ (uDst << 1)); /* Set according to the first shift. */ \
     2705        fEfl |= (uDst >> (a_cBitsWidth - cShift)) & X86_EFL_CF; /* CF = last bit shifted out */ \
     2706        fEfl |= g_afParity[uResult & 0xff]; \
     2707        fEfl |= X86_EFL_CALC_SF(uResult, a_cBitsWidth); \
     2708        fEfl |= X86_EFL_CALC_ZF(uResult); \
     2709        *pfEFlags = fEfl; \
     2710    } \
     2711}\
     2712\
     2713IEM_DECL_IMPL_DEF(void, iemAImpl_shld_u ## a_cBitsWidth ## _intel,(uint ## a_cBitsWidth ## _t *puDst, \
     2714                                                                   uint ## a_cBitsWidth ## _t uSrc, uint8_t cShift, \
     2715                                                                   uint32_t *pfEFlags)) \
     2716{ \
     2717    iemAImpl_shld_u ## a_cBitsWidth(puDst, uSrc, cShift, pfEFlags); \
     2718} \
     2719\
     2720IEM_DECL_IMPL_DEF(void, iemAImpl_shld_u ## a_cBitsWidth ## _amd,(uint ## a_cBitsWidth ## _t *puDst, \
     2721                                                                 uint ## a_cBitsWidth ## _t uSrc, uint8_t cShift, \
     2722                                                                 uint32_t *pfEFlags)) \
     2723{ \
     2724    cShift &= a_cBitsWidth - 1; \
     2725    if (cShift) \
     2726    { \
     2727        uint ## a_cBitsWidth ## _t const uDst    = *puDst; \
     2728        uint ## a_cBitsWidth ## _t       uResult = uDst << cShift; \
     2729        uResult |= uSrc >> (a_cBitsWidth - cShift); \
     2730        *puDst = uResult; \
     2731        \
     2732        uint32_t fEfl = *pfEFlags & ~X86_EFL_STATUS_BITS; \
     2733        fEfl |= X86_EFL_GET_OF_ ## a_cBitsWidth((uDst << (cShift - 1)) ^ uResult); /* Set according to last shift. */ \
     2734        fEfl |= X86_EFL_AF; \
    27102735        AssertCompile(X86_EFL_CF_BIT == 0); \
    27112736        fEfl |= (uDst >> (a_cBitsWidth - cShift)) & X86_EFL_CF; /* CF = last bit shifted out */ \
     
    27162741    } \
    27172742}
     2743
    27182744EMIT_SHLD(64)
    27192745# if !defined(RT_ARCH_X86) || defined(IEM_WITHOUT_ASSEMBLY)
     
    27252751/*
    27262752 * SHRD
     2753 *
     2754 * EFLAGS behaviour seems to be the same as with SHLD:
     2755 *  - CF is the last bit shifted out of puDst.
     2756 *  - AF is always cleared by Intel 10980XE.
     2757 *  - AF is always set by AMD 3990X.
     2758 *  - OF is set according to the first shift on Intel 10980XE, it seems.
     2759 *  - OF is set according to the last sub-shift on AMD 3990X.
     2760 *  - ZF, SF and PF are calculated according to the result by both vendors.
    27272761 */
    27282762#define EMIT_SHRD(a_cBitsWidth) \
    27292763IEM_DECL_IMPL_DEF(void, iemAImpl_shrd_u ## a_cBitsWidth,(uint ## a_cBitsWidth ## _t *puDst, \
    27302764                                                         uint ## a_cBitsWidth ## _t uSrc, uint8_t cShift, uint32_t *pfEFlags)) \
     2765{ \
     2766    /** @todo this is wrong for 16-bit, where it should be 0x1f not 0xf and \
     2767     *        source used twice or something like that. */ \
     2768    cShift &= a_cBitsWidth - 1; \
     2769    if (cShift) \
     2770    { \
     2771        uint ## a_cBitsWidth ## _t const uDst    = *puDst; \
     2772        uint ## a_cBitsWidth ## _t       uResult = uDst >> cShift; \
     2773        uResult |= uSrc << (a_cBitsWidth - cShift); \
     2774        *puDst = uResult; \
     2775        \
     2776        uint32_t fEfl = *pfEFlags & ~X86_EFL_STATUS_BITS; \
     2777        fEfl |= X86_EFL_GET_OF_ ## a_cBitsWidth(uDst ^ (uSrc << (a_cBitsWidth - 1))); \
     2778        AssertCompile(X86_EFL_CF_BIT == 0); \
     2779        fEfl |= (uDst >> (cShift - 1)) & X86_EFL_CF; \
     2780        fEfl |= X86_EFL_CALC_SF(uResult, a_cBitsWidth); \
     2781        fEfl |= X86_EFL_CALC_ZF(uResult); \
     2782        fEfl |= g_afParity[uResult & 0xff]; \
     2783        *pfEFlags = fEfl; \
     2784    } \
     2785} \
     2786\
     2787IEM_DECL_IMPL_DEF(void, iemAImpl_shrd_u ## a_cBitsWidth ## _intel,(uint ## a_cBitsWidth ## _t *puDst, \
     2788                                                                   uint ## a_cBitsWidth ## _t uSrc, uint8_t cShift, \
     2789                                                                   uint32_t *pfEFlags)) \
     2790{ \
     2791    iemAImpl_shrd_u ## a_cBitsWidth(puDst, uSrc, cShift, pfEFlags); \
     2792} \
     2793\
     2794IEM_DECL_IMPL_DEF(void, iemAImpl_shrd_u ## a_cBitsWidth ## _amd,(uint ## a_cBitsWidth ## _t *puDst, \
     2795                                                                 uint ## a_cBitsWidth ## _t uSrc, uint8_t cShift, \
     2796                                                                 uint32_t *pfEFlags)) \
    27312797{ \
    27322798    cShift &= a_cBitsWidth - 1; \
     
    27382804        *puDst = uResult; \
    27392805        \
    2740         /* Calc EFLAGS.  CF is the last bit shifted out of puDst. The OF flag \
    2741            indicates a sign change for a single shift, whereas intel documents \
    2742            setting it to zero for higher shift counts and AMD just says it's \
    2743            undefined, however AMD x3990 sets it according to the last sub-shift. \
    2744            On AMD x3990 the AF flag is always set. */ \
    27452806        uint32_t fEfl = *pfEFlags & ~X86_EFL_STATUS_BITS; \
    2746         if (true /*AMD*/) \
    2747         { \
    2748             if (cShift > 1) /* Set according to last shift. */ \
    2749                 fEfl |= X86_EFL_GET_OF_ ## a_cBitsWidth((uSrc << (a_cBitsWidth - cShift + 1)) ^ uResult); \
    2750             else \
    2751                 fEfl |= X86_EFL_GET_OF_ ## a_cBitsWidth(uDst ^ uResult); \
    2752             fEfl |= X86_EFL_AF; \
    2753         } \
     2807        if (cShift > 1) /* Set according to last shift. */ \
     2808            fEfl |= X86_EFL_GET_OF_ ## a_cBitsWidth((uSrc << (a_cBitsWidth - cShift + 1)) ^ uResult); \
    27542809        else \
    2755         { \
    2756             if (cShift == 1) \
    2757                 fEfl |= X86_EFL_GET_OF_ ## a_cBitsWidth((uDst >> (a_cBitsWidth - 1)) ^ (uint32_t)(uResult >> (a_cBitsWidth - 1))); \
    2758             fEfl |= X86_EFL_AF; /* ? */ \
    2759         } \
     2810            fEfl |= X86_EFL_GET_OF_ ## a_cBitsWidth(uDst ^ uResult); \
     2811        fEfl |= X86_EFL_AF; \
    27602812        AssertCompile(X86_EFL_CF_BIT == 0); \
    27612813        fEfl |= (uDst >> (cShift - 1)) & X86_EFL_CF; \
  • trunk/src/VBox/VMM/VMMAll/IEMAllInstructionsTwoByte0f.cpp.h

    r94156 r94162  
    67266726    IEMOP_MNEMONIC(shld_Ev_Gv_Ib, "shld Ev,Gv,Ib");
    67276727    IEMOP_HLP_MIN_386();
    6728     return FNIEMOP_CALL_1(iemOpCommonShldShrd_Ib, &g_iemAImpl_shld);
     6728    return FNIEMOP_CALL_1(iemOpCommonShldShrd_Ib, IEMTARGETCPU_EFL_BEHAVIOR_SELECT(g_iemAImpl_shld_eflags));
    67296729}
    67306730
     
    67356735    IEMOP_MNEMONIC(shld_Ev_Gv_CL, "shld Ev,Gv,CL");
    67366736    IEMOP_HLP_MIN_386();
    6737     return FNIEMOP_CALL_1(iemOpCommonShldShrd_CL, &g_iemAImpl_shld);
     6737    return FNIEMOP_CALL_1(iemOpCommonShldShrd_CL, IEMTARGETCPU_EFL_BEHAVIOR_SELECT(g_iemAImpl_shld_eflags));
    67386738}
    67396739
     
    67846784    IEMOP_MNEMONIC(shrd_Ev_Gv_Ib, "shrd Ev,Gv,Ib");
    67856785    IEMOP_HLP_MIN_386();
    6786     return FNIEMOP_CALL_1(iemOpCommonShldShrd_Ib, &g_iemAImpl_shrd);
     6786    return FNIEMOP_CALL_1(iemOpCommonShldShrd_Ib, IEMTARGETCPU_EFL_BEHAVIOR_SELECT(g_iemAImpl_shrd_eflags));
    67876787}
    67886788
     
    67936793    IEMOP_MNEMONIC(shrd_Ev_Gv_CL, "shrd Ev,Gv,CL");
    67946794    IEMOP_HLP_MIN_386();
    6795     return FNIEMOP_CALL_1(iemOpCommonShldShrd_CL, &g_iemAImpl_shrd);
     6795    return FNIEMOP_CALL_1(iemOpCommonShldShrd_CL, IEMTARGETCPU_EFL_BEHAVIOR_SELECT(g_iemAImpl_shrd_eflags));
    67966796}
    67976797
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette