VirtualBox

Changeset 47379 in vbox for trunk


Ignore:
Timestamp:
Jul 24, 2013 5:21:12 PM (12 years ago)
Author:
vboxsync
Message:

IEM: syscall and sysret.

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

Legend:

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

    r47350 r47379  
    27232723
    27242724/**
     2725 * Implements SYSCALL (AMD and Intel64).
     2726 *
     2727 * @param   enmEffOpSize    The effective operand size.
     2728 */
     2729IEM_CIMPL_DEF_0(iemCImpl_syscall)
     2730{
     2731    PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
     2732
     2733    /*
     2734     * Check preconditions.
     2735     *
     2736     * Note that CPUs described in the documentation may load a few odd values
     2737     * into CS and SS than we allow here.  This has yet to be checked on real
     2738     * hardware.
     2739     */
     2740    if (!(pCtx->msrEFER & MSR_K6_EFER_SCE))
     2741    {
     2742        Log(("syscall: Not enabled in EFER -> #UD\n"));
     2743        return iemRaiseUndefinedOpcode(pIemCpu);
     2744    }
     2745    if (!(pCtx->cr0 & X86_CR0_PE))
     2746    {
     2747        Log(("syscall: Protected mode is required -> #GP(0)\n"));
     2748        return iemRaiseGeneralProtectionFault0(pIemCpu);
     2749    }
     2750    if (IEM_IS_GUEST_CPU_INTEL(pIemCpu) && !CPUMIsGuestInLongModeEx(pCtx))
     2751    {
     2752        Log(("syscall: Only available in long mode on intel -> #UD\n"));
     2753        return iemRaiseUndefinedOpcode(pIemCpu);
     2754    }
     2755
     2756    /** @todo verify RPL ignoring and CS=0xfff8 (i.e. SS == 0). */
     2757    /** @todo what about LDT selectors? Shouldn't matter, really. */
     2758    uint16_t uNewCs = (pCtx->msrSTAR >> MSR_K6_STAR_SYSCALL_CS_SS_SHIFT) & X86_SEL_MASK_OFF_RPL;
     2759    uint16_t uNewSs = uNewCs + 8;
     2760    if (uNewCs == 0 || uNewSs == 0)
     2761    {
     2762        Log(("syscall: msrSTAR.CS = 0 or SS = 0 -> #GP(0)\n"));
     2763        return iemRaiseGeneralProtectionFault0(pIemCpu);
     2764    }
     2765
     2766    /* Long mode and legacy mode differs. */
     2767    if (CPUMIsGuestInLongModeEx(pCtx))
     2768    {
     2769        uint64_t uNewRip = pIemCpu->enmCpuMode == IEMMODE_64BIT ? pCtx->msrLSTAR : pCtx-> msrCSTAR;
     2770
     2771        /* This test isn't in the docs, but I'm not trusting the guys writing
     2772           the MSRs to have validated the values as canonical like they should. */
     2773        if (!IEM_IS_CANONICAL(uNewRip))
     2774        {
     2775            Log(("syscall: Only available in long mode on intel -> #UD\n"));
     2776            return iemRaiseUndefinedOpcode(pIemCpu);
     2777        }
     2778
     2779        /*
     2780         * Commit it.
     2781         */
     2782        Log(("syscall: %04x:%016RX64 [efl=%#llx] -> %04x:%016RX64\n", pCtx->cs, pCtx->rip, pCtx->rflags.u, uNewCs, uNewRip));
     2783        pCtx->rcx           = pCtx->rip + cbInstr;
     2784        pCtx->rip           = uNewRip;
     2785
     2786        pCtx->rflags.u     &= ~X86_EFL_RF;
     2787        pCtx->r11           = pCtx->rflags.u;
     2788        pCtx->rflags.u     &= ~pCtx->msrSFMASK;
     2789        pCtx->rflags.u     |= X86_EFL_1;
     2790
     2791        pCtx->cs.Attr.u     = X86DESCATTR_P | X86DESCATTR_G | X86DESCATTR_L | X86DESCATTR_DT | X86_SEL_TYPE_ER_ACC;
     2792        pCtx->ss.Attr.u     = X86DESCATTR_P | X86DESCATTR_G | X86DESCATTR_L | X86DESCATTR_DT | X86_SEL_TYPE_RW_ACC;
     2793    }
     2794    else
     2795    {
     2796        /*
     2797         * Commit it.
     2798         */
     2799        Log(("syscall: %04x:%08RX32 [efl=%#x] -> %04x:%08RX32\n",
     2800             pCtx->cs, pCtx->eip, pCtx->eflags.u, uNewCs, (uint32_t)(pCtx->msrSTAR & MSR_K6_STAR_SYSCALL_EIP_MASK)));
     2801        pCtx->rcx           = pCtx->eip + cbInstr;
     2802        pCtx->rip           = pCtx->msrSTAR & MSR_K6_STAR_SYSCALL_EIP_MASK;
     2803        pCtx->rflags.u     &= ~(X86_EFL_VM | X86_EFL_IF | X86_EFL_RF);
     2804
     2805        pCtx->cs.Attr.u     = X86DESCATTR_P | X86DESCATTR_G | X86DESCATTR_D | X86DESCATTR_DT | X86_SEL_TYPE_ER_ACC;
     2806        pCtx->ss.Attr.u     = X86DESCATTR_P | X86DESCATTR_G | X86DESCATTR_D | X86DESCATTR_DT | X86_SEL_TYPE_RW_ACC;
     2807    }
     2808    pCtx->cs.Sel        = uNewCs;
     2809    pCtx->cs.ValidSel   = uNewCs;
     2810    pCtx->cs.u64Base    = 0;
     2811    pCtx->cs.u32Limit   = UINT32_MAX;
     2812    pCtx->cs.fFlags     = CPUMSELREG_FLAGS_VALID;
     2813
     2814    pCtx->ss.Sel        = uNewSs;
     2815    pCtx->ss.ValidSel   = uNewSs;
     2816    pCtx->ss.u64Base    = 0;
     2817    pCtx->ss.u32Limit   = UINT32_MAX;
     2818    pCtx->ss.fFlags     = CPUMSELREG_FLAGS_VALID;
     2819
     2820    return VINF_SUCCESS;
     2821}
     2822
     2823
     2824/**
     2825 * Implements SYSRET (AMD and Intel64).
     2826 */
     2827IEM_CIMPL_DEF_0(iemCImpl_sysret)
     2828
     2829{
     2830    PCPUMCTX pCtx = pIemCpu->CTX_SUFF(pCtx);
     2831
     2832    /*
     2833     * Check preconditions.
     2834     *
     2835     * Note that CPUs described in the documentation may load a few odd values
     2836     * into CS and SS than we allow here.  This has yet to be checked on real
     2837     * hardware.
     2838     */
     2839    if (!(pCtx->msrEFER & MSR_K6_EFER_SCE))
     2840    {
     2841        Log(("sysret: Not enabled in EFER -> #UD\n"));
     2842        return iemRaiseUndefinedOpcode(pIemCpu);
     2843    }
     2844    if (IEM_IS_GUEST_CPU_INTEL(pIemCpu) && !CPUMIsGuestInLongModeEx(pCtx))
     2845    {
     2846        Log(("sysret: Only available in long mode on intel -> #UD\n"));
     2847        return iemRaiseUndefinedOpcode(pIemCpu);
     2848    }
     2849    if (!(pCtx->cr0 & X86_CR0_PE))
     2850    {
     2851        Log(("sysret: Protected mode is required -> #GP(0)\n"));
     2852        return iemRaiseGeneralProtectionFault0(pIemCpu);
     2853    }
     2854    if (pIemCpu->uCpl != 0)
     2855    {
     2856        Log(("sysret: CPL must be 0 not %u -> #GP(0)\n", pIemCpu->uCpl));
     2857        return iemRaiseGeneralProtectionFault0(pIemCpu);
     2858    }
     2859
     2860    /** @todo Does SYSRET verify CS != 0 and SS != 0? Neither is valid in ring-3. */
     2861    uint16_t uNewCs = (pCtx->msrSTAR >> MSR_K6_STAR_SYSRET_CS_SS_SHIFT) & X86_SEL_MASK_OFF_RPL;
     2862    uint16_t uNewSs = uNewCs + 8;
     2863    if (pIemCpu->enmEffOpSize == IEMMODE_64BIT)
     2864        uNewCs += 16;
     2865    if (uNewCs == 0 || uNewSs == 0)
     2866    {
     2867        Log(("sysret: msrSTAR.CS = 0 or SS = 0 -> #GP(0)\n"));
     2868        return iemRaiseGeneralProtectionFault0(pIemCpu);
     2869    }
     2870
     2871    /*
     2872     * Commit it.
     2873     */
     2874    if (CPUMIsGuestInLongModeEx(pCtx))
     2875    {
     2876        if (pIemCpu->enmEffOpSize == IEMMODE_64BIT)
     2877        {
     2878            Log(("sysret: %04x:%016RX64 [efl=%#llx] -> %04x:%016RX64 [r11=%#llx]\n",
     2879                 pCtx->cs, pCtx->rip, pCtx->rflags.u, uNewCs, pCtx->rcx, pCtx->r11));
     2880            /* Note! We disregard intel manual regarding the RCX cananonical
     2881                     check, ask intel+xen why AMD doesn't do it. */
     2882            pCtx->rip       = pCtx->rcx;
     2883            pCtx->cs.Attr.u = X86DESCATTR_P | X86DESCATTR_G | X86DESCATTR_L | X86DESCATTR_DT | X86_SEL_TYPE_ER_ACC
     2884                            | (3 << X86DESCATTR_DPL_SHIFT);
     2885        }
     2886        else
     2887        {
     2888            Log(("sysret: %04x:%016RX64 [efl=%#llx] -> %04x:%08RX32 [r11=%#llx]\n",
     2889                 pCtx->cs, pCtx->rip, pCtx->rflags.u, uNewCs, pCtx->ecx, pCtx->r11));
     2890            pCtx->rip       = pCtx->ecx;
     2891            pCtx->cs.Attr.u = X86DESCATTR_P | X86DESCATTR_G | X86DESCATTR_D | X86DESCATTR_DT | X86_SEL_TYPE_ER_ACC
     2892                            | (3 << X86DESCATTR_DPL_SHIFT);
     2893        }
     2894        /** @todo testcase: See what kind of flags we can make SYSRET restore and
     2895         *        what it really ignores. RF and VM are hinted at being zero, by AMD. */
     2896        pCtx->rflags.u      = pCtx->r11 & (X86_EFL_POPF_BITS | X86_EFL_VIF | X86_EFL_VIP);
     2897        pCtx->rflags.u     |= X86_EFL_1;
     2898    }
     2899    else
     2900    {
     2901        Log(("sysret: %04x:%08RX32 [efl=%#x] -> %04x:%08RX32\n", pCtx->cs, pCtx->eip, pCtx->eflags.u, uNewCs, pCtx->ecx));
     2902        pCtx->rip           = pCtx->rcx;
     2903        pCtx->rflags.u     |= X86_EFL_IF;
     2904        pCtx->cs.Attr.u     = X86DESCATTR_P | X86DESCATTR_G | X86DESCATTR_D | X86DESCATTR_DT | X86_SEL_TYPE_ER_ACC
     2905                            | (3 << X86DESCATTR_DPL_SHIFT);
     2906    }
     2907    pCtx->cs.Sel        = uNewCs | 3;
     2908    pCtx->cs.ValidSel   = uNewCs | 3;
     2909    pCtx->cs.u64Base    = 0;
     2910    pCtx->cs.u32Limit   = UINT32_MAX;
     2911    pCtx->cs.fFlags     = CPUMSELREG_FLAGS_VALID;
     2912
     2913    pCtx->ss.Sel        = uNewSs | 3;
     2914    pCtx->ss.ValidSel   = uNewSs | 3;
     2915    pCtx->ss.fFlags     = CPUMSELREG_FLAGS_VALID;
     2916    /* The SS hidden bits remains unchanged says AMD. To that I say "Yeah, right!". */
     2917    pCtx->ss.Attr.u    |= (3 << X86DESCATTR_DPL_SHIFT);
     2918    /** @todo Testcase: verify that SS.u1Long and SS.u1DefBig are left unchanged
     2919     *        on sysret. */
     2920
     2921    return VINF_SUCCESS;
     2922}
     2923
     2924
     2925/**
    27252926 * Common worker for 'pop SReg', 'mov SReg, GReg' and 'lXs GReg, reg/mem'.
    27262927 *
     
    36483849            if (   (uOldCrX & X86_CR4_PAE)
    36493850                && !(uNewCrX & X86_CR4_PAE)
    3650                 && (pCtx->msrEFER & MSR_K6_EFER_LMA) )
     3851                && CPUMIsGuestInLongModeEx(pCtx) )
    36513852            {
    36523853                Log(("Trying to set clear CR4.PAE while long mode is active\n"));
  • trunk/src/VBox/VMM/VMMAll/IEMAllInstructions.cpp.h

    r47350 r47379  
    11011101/** Opcode 0x0f 0x03. */
    11021102FNIEMOP_STUB(iemOp_lsl_Gv_Ew);
     1103
     1104
    11031105/** Opcode 0x0f 0x04. */
    1104 FNIEMOP_STUB(iemOp_syscall);
     1106FNIEMOP_DEF(iemOp_syscall)
     1107{
     1108    IEMOP_MNEMONIC("syscall");
     1109    IEMOP_HLP_NO_LOCK_PREFIX();
     1110    return IEM_MC_DEFER_TO_CIMPL_0(iemCImpl_syscall);
     1111}
    11051112
    11061113
     
    11151122
    11161123/** Opcode 0x0f 0x06. */
    1117 FNIEMOP_STUB(iemOp_sysret);
     1124FNIEMOP_DEF(iemOp_sysret)
     1125{
     1126    IEMOP_MNEMONIC("sysret");
     1127    IEMOP_HLP_NO_LOCK_PREFIX();
     1128    return IEM_MC_DEFER_TO_CIMPL_0(iemCImpl_sysret);
     1129}
     1130
     1131
    11181132/** Opcode 0x0f 0x08. */
    11191133FNIEMOP_STUB(iemOp_invd);
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