VirtualBox

Changeset 1478 in vbox for trunk


Ignore:
Timestamp:
Mar 14, 2007 5:30:12 PM (18 years ago)
Author:
vboxsync
Message:

Support VME in guests. (v86 extensions)

Location:
trunk/src/recompiler/target-i386
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/recompiler/target-i386/exec.h

    r1 r1478  
    238238void OPPROTO op_movl_eflags_T0(void);
    239239void OPPROTO op_movl_T0_eflags(void);
     240#ifdef VBOX
     241void OPPROTO op_movl_T0_eflags_vme(void);
     242void OPPROTO op_movw_eflags_T0_vme(void);
     243void OPPROTO op_cli_vme(void);
     244void OPPROTO op_sti_vme(void);
     245#endif
    240246void helper_divl_EAX_T0(void);
    241247void helper_idivl_EAX_T0(void);
  • trunk/src/recompiler/target-i386/helper.c

    r1093 r1478  
    803803    env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK);
    804804}
     805
     806#ifdef VBOX
     807
     808/* check if VME interrupt redirection is enabled in TSS */
     809static inline bool is_vme_irq_redirected(int intno)
     810{
     811    int io_offset, intredir_offset;
     812    unsigned char val, mask;
     813   
     814    /* TSS must be a valid 32 bit one */
     815    if (!(env->tr.flags & DESC_P_MASK) ||
     816        ((env->tr.flags >> DESC_TYPE_SHIFT) & 0xf) != 9 ||
     817        env->tr.limit < 103)
     818        goto fail;
     819    io_offset = lduw_kernel(env->tr.base + 0x66);
     820    /* the virtual interrupt redirection bitmap is located below the io bitmap */
     821    intredir_offset = io_offset - 0x20;
     822   
     823    intredir_offset += (intno >> 3);
     824    if ((intredir_offset) > env->tr.limit)
     825        goto fail;
     826
     827    val = ldub_kernel(env->tr.base + intredir_offset);
     828    mask = 1 << (unsigned char)(intno & 7);
     829
     830    /* bit set means no redirection. */
     831    if ((val & mask) != 0) {
     832        return false;
     833    }
     834    return true;
     835
     836fail:
     837    raise_exception_err(EXCP0D_GPF, 0);
     838    return true;
     839}
     840
     841/* V86 mode software interrupt with CR4.VME=1 */
     842static void do_soft_interrupt_vme(int intno, int error_code, unsigned int next_eip)
     843{
     844    target_ulong ptr, ssp;
     845    int selector;
     846    uint32_t offset, esp;
     847    uint32_t old_cs, old_eflags;
     848    uint32_t iopl;
     849
     850    iopl = ((env->eflags >> IOPL_SHIFT) & 3);
     851
     852    if (!is_vme_irq_redirected(intno))
     853    {
     854        if (iopl == 3)
     855            /* normal protected mode handler call */
     856            return do_interrupt_protected(intno, 1, error_code, next_eip, 0);
     857        else
     858            raise_exception_err(EXCP0D_GPF, 0);
     859    }
     860
     861    /* virtual mode idt is at linear address 0 */
     862    ptr = 0 + intno * 4;
     863    offset = lduw_kernel(ptr);
     864    selector = lduw_kernel(ptr + 2);
     865    esp = ESP;
     866    ssp = env->segs[R_SS].base;
     867    old_cs = env->segs[R_CS].selector;
     868
     869    old_eflags = compute_eflags();
     870    if (iopl < 3)
     871    {
     872        /* copy VIF into IF and set IOPL to 3 */
     873        if (env->eflags & VIF_MASK)
     874            old_eflags |= IF_MASK;
     875        else
     876            old_eflags &= ~IF_MASK;
     877
     878        old_eflags |= (3 << IOPL_SHIFT);
     879    }
     880
     881    /* XXX: use SS segment size ? */
     882    PUSHW(ssp, esp, 0xffff, old_eflags);
     883    PUSHW(ssp, esp, 0xffff, old_cs);
     884    PUSHW(ssp, esp, 0xffff, next_eip);
     885   
     886    /* update processor state */
     887    ESP = (ESP & ~0xffff) | (esp & 0xffff);
     888    env->eip = offset;
     889    env->segs[R_CS].selector = selector;
     890    env->segs[R_CS].base = (selector << 4);
     891    env->eflags &= ~(TF_MASK | RF_MASK);
     892
     893    if (iopl < 3)
     894        env->eflags &= ~IF_MASK;
     895    else
     896        env->eflags &= ~VIF_MASK;
     897}
     898#endif
    805899
    806900#ifdef TARGET_X86_64
     
    12241318#endif
    12251319        {
    1226             do_interrupt_protected(intno, is_int, error_code, next_eip, is_hw);
     1320#ifdef VBOX
     1321            /* int xx *, v86 code and VME enabled? */
     1322            if (    !is_hw
     1323                &&  is_int
     1324                &&  env->eip + 1 != next_eip /* single byte int 3 goes straight to the protected mode handler */
     1325                &&  (env->eflags & VM_MASK)
     1326                &&  (env->cr[4] & CR4_VME_MASK)
     1327               )
     1328                do_soft_interrupt_vme(intno, error_code, next_eip);
     1329            else
     1330#endif
     1331                do_interrupt_protected(intno, is_int, error_code, next_eip, is_hw);
    12271332        }
    12281333    } else {
     
    20092114
    20102115#ifdef VBOX
     2116    bool fVME = false;
     2117
    20112118    remR3TrapClear(env->pVM);
    20122119#endif
     
    20272134        POPW(ssp, sp, sp_mask, new_eflags);
    20282135    }
     2136#ifdef VBOX
     2137    if (    (env->eflags & VM_MASK)
     2138        &&  ((env->eflags >> IOPL_SHIFT) & 3) != 3
     2139        &&  (env->cr[4] & CR4_VME_MASK)) /* implied or else we would fault earlier */
     2140    {
     2141        fVME = true;
     2142        /* if virtual interrupt pending and (virtual) interrupts will be enabled -> #GP */
     2143        /* if TF will be set -> #GP */
     2144        if (    ((new_eflags & IF_MASK) && (env->eflags & VIP_MASK))
     2145            ||  (new_eflags & TF_MASK))
     2146        {
     2147            raise_exception(EXCP0D_GPF);
     2148        }
     2149    }
     2150#endif
     2151
    20292152    ESP = (ESP & ~sp_mask) | (sp & sp_mask);
    20302153    load_seg_vm(R_CS, new_cs);
    20312154    env->eip = new_eip;
     2155#ifdef VBOX
     2156    if (fVME)
     2157        eflags_mask = TF_MASK | AC_MASK | ID_MASK | RF_MASK | NT_MASK;
     2158    else
     2159#endif
    20322160    if (env->eflags & VM_MASK)
    20332161        eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | RF_MASK | NT_MASK;
     
    20362164    if (shift == 0)
    20372165        eflags_mask &= 0xffff;
     2166
    20382167    load_eflags(new_eflags, eflags_mask);
     2168
     2169#ifdef VBOX
     2170    if (fVME)
     2171    {
     2172        if (new_eflags & IF_MASK)
     2173            env->eflags |= VIF_MASK;
     2174        else
     2175            env->eflags &= ~VIF_MASK;
     2176    }
     2177#endif
    20392178}
    20402179
  • trunk/src/recompiler/target-i386/op.c

    r1 r1478  
    721721}
    722722
    723 #if 0
     723#ifdef VBOX
    724724/* vm86plus instructions */
    725 void OPPROTO op_cli_vm(void)
     725void OPPROTO op_cli_vme(void)
    726726{
    727727    env->eflags &= ~VIF_MASK;
    728728}
    729729
    730 void OPPROTO op_sti_vm(void)
    731 {
    732     env->eflags |= VIF_MASK;
     730void OPPROTO op_sti_vme(void)
     731{
     732    /* First check, then change eflags according to the AMD manual */
    733733    if (env->eflags & VIP_MASK) {
    734         EIP = PARAM1;
    735734        raise_exception(EXCP0D_GPF);
    736735    }
     736    env->eflags |= VIF_MASK;
    737737    FORCE_RET();
    738738}
     
    14631463
    14641464/* XXX: clear VIF/VIP in all ops ? */
     1465#ifdef VBOX
     1466/* XXX: AMD docs say they remain unchanged. */
     1467#endif
    14651468
    14661469void OPPROTO op_movl_eflags_T0(void)
     
    14941497}
    14951498
     1499/* vm86plus version */
     1500#ifdef VBOX
     1501/* IOPL != 3, CR4.VME=1 */
     1502void OPPROTO op_movw_eflags_T0_vme(void)
     1503{
     1504    unsigned int new_eflags = T0;
     1505
     1506    /* if virtual interrupt pending and (virtual) interrupts will be enabled -> #GP */
     1507    /* if TF will be set -> #GP */
     1508    if (    ((new_eflags & IF_MASK) && (env->eflags & VIP_MASK))
     1509        ||  (new_eflags & TF_MASK))
     1510    {
     1511        raise_exception(EXCP0D_GPF);
     1512    }
     1513    else
     1514    {
     1515        load_eflags(new_eflags, (TF_MASK | AC_MASK | ID_MASK | NT_MASK) & 0xffff);
     1516
     1517        if (new_eflags & IF_MASK)
     1518            env->eflags |= VIF_MASK;
     1519        else
     1520            env->eflags &= ~VIF_MASK;
     1521    }
     1522
     1523    FORCE_RET();
     1524}
     1525#endif
     1526
    14961527#if 0
    1497 /* vm86plus version */
    1498 void OPPROTO op_movw_eflags_T0_vm(void)
    1499 {
    1500     int eflags;
    1501     eflags = T0;
    1502     CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
    1503     DF = 1 - (2 * ((eflags >> 10) & 1));
    1504     /* we also update some system flags as in user mode */
    1505     env->eflags = (env->eflags & ~(FL_UPDATE_MASK16 | VIF_MASK)) |
    1506         (eflags & FL_UPDATE_MASK16);
    1507     if (eflags & IF_MASK) {
    1508         env->eflags |= VIF_MASK;
    1509         if (env->eflags & VIP_MASK) {
    1510             EIP = PARAM1;
    1511             raise_exception(EXCP0D_GPF);
    1512         }
    1513     }
    1514     FORCE_RET();
    1515 }
    1516 
    15171528void OPPROTO op_movl_eflags_T0_vm(void)
    15181529{
     
    15531564
    15541565/* vm86plus version */
    1555 #if 0
    1556 void OPPROTO op_movl_T0_eflags_vm(void)
     1566#ifdef VBOX
     1567void OPPROTO op_movl_T0_eflags_vme(void)
    15571568{
    15581569    int eflags;
  • trunk/src/recompiler/target-i386/translate.c

    r1 r1478  
    119119    int f_st;   /* currently unused */
    120120    int vm86;   /* vm86 mode */
     121#ifdef VBOX
     122    int vme;    /* CR4.VME */
     123#endif
    121124    int cpl;
    122125    int iopl;
     
    49694972            s->cc_op = CC_OP_EFLAGS;
    49704973        } else if (s->vm86) {
     4974#ifdef VBOX
     4975            if (s->iopl != 3 && (!s->vme || s->dflag)) {
     4976#else
    49714977            if (s->iopl != 3) {
     4978#endif
    49724979                gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
    49734980            } else {
     
    50855092        /* flags */
    50865093    case 0x9c: /* pushf */
     5094#ifdef VBOX
     5095        if (s->vm86 && s->iopl != 3 && (!s->vme || s->dflag)) {
     5096#else
    50875097        if (s->vm86 && s->iopl != 3) {
     5098#endif
    50885099            gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
    50895100        } else {
    50905101            if (s->cc_op != CC_OP_DYNAMIC)
    50915102                gen_op_set_cc_op(s->cc_op);
    5092             gen_op_movl_T0_eflags();
     5103#ifdef VBOX
     5104            if (s->vm86 && s->vme && s->iopl != 3)
     5105                gen_op_movl_T0_eflags_vme();
     5106            else
     5107#endif
     5108                gen_op_movl_T0_eflags();
    50935109            gen_push_T0(s);
    50945110        }
    50955111        break;
    50965112    case 0x9d: /* popf */
     5113#ifdef VBOX
     5114        if (s->vm86 && s->iopl != 3 && (!s->vme || s->dflag)) {
     5115#else
    50975116        if (s->vm86 && s->iopl != 3) {
     5117#endif
    50985118            gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
    50995119        } else {
     
    51165136                        gen_op_movl_eflags_T0();
    51175137                    } else {
    5118                         gen_op_movw_eflags_T0();
     5138#ifdef VBOX
     5139                        if (s->vm86 && s->vme)
     5140                            gen_op_movw_eflags_T0_vme();
     5141                        else
     5142#endif
     5143                            gen_op_movw_eflags_T0();
    51195144                    }
    51205145                }
     
    53175342        break;
    53185343    case 0xcc: /* int3 */
    5319         gen_interrupt(s, EXCP03_INT3, pc_start - s->cs_base, s->pc - s->cs_base);
     5344#ifdef VBOX
     5345        if (s->vm86 && s->iopl != 3 && !s->vme) {
     5346            gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
     5347        }
     5348        else
     5349#endif
     5350            gen_interrupt(s, EXCP03_INT3, pc_start - s->cs_base, s->pc - s->cs_base);
    53205351        break;
    53215352    case 0xcd: /* int N */
    53225353        val = ldub_code(s->pc++);
     5354#ifdef VBOX
     5355        if (s->vm86 && s->iopl != 3 && !s->vme) {
     5356#else
    53235357        if (s->vm86 && s->iopl != 3) {
     5358#endif
    53245359            gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
    53255360        } else {
     
    53485383            if (s->iopl == 3) {
    53495384                gen_op_cli();
     5385#ifdef VBOX
     5386            } else
     5387            if (s->iopl != 3 && s->vme) {
     5388                gen_op_cli_vme();
     5389#endif
    53505390            } else {
    53515391                gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
     
    53725412            if (s->iopl == 3) {
    53735413                goto gen_sti;
     5414#ifdef VBOX
     5415            } else
     5416            if (s->iopl != 3 && s->vme) {
     5417                gen_op_sti_vme();
     5418                /* give a chance to handle pending irqs */
     5419                gen_jmp_im(s->pc - s->cs_base);
     5420                gen_eob(s);
     5421#endif
    53745422            } else {
    53755423                gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
     
    64126460    dc->f_st = 0;
    64136461    dc->vm86 = (flags >> VM_SHIFT) & 1;
     6462#ifdef VBOX
     6463    dc->vme = !!(env->cr[4] & CR4_VME_MASK);
     6464#endif
    64146465    dc->cpl = (flags >> HF_CPL_SHIFT) & 3;
    64156466    dc->iopl = (flags >> IOPL_SHIFT) & 3;
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