x86_emulate.c

来自「xen虚拟机源代码安装包」· C语言 代码 · 共 1,781 行 · 第 1/5 页

C
1,781
字号
          : "=a" (m[0]), "=d" (m[1]), "=q" (rc)          : "0" (m[0]), "1" (m[1]), "2" (0) );    return rc;}/* * Signed multiplication with double-word result. * IN:  Multiplicand=m[0], Multiplier=m[1] * OUT: Return CF/OF (overflow status); Result=m[1]:m[0] */static int imul_dbl(unsigned long m[2]){    int rc;    asm ( "imul %4; seto %b2"          : "=a" (m[0]), "=d" (m[1]), "=q" (rc)          : "0" (m[0]), "1" (m[1]), "2" (0) );    return rc;}/* * Unsigned division of double-word dividend. * IN:  Dividend=u[1]:u[0], Divisor=v * OUT: Return 1: #DE *      Return 0: Quotient=u[0], Remainder=u[1] */static int div_dbl(unsigned long u[2], unsigned long v){    if ( (v == 0) || (u[1] >= v) )        return 1;    asm ( "div %4"          : "=a" (u[0]), "=d" (u[1])          : "0" (u[0]), "1" (u[1]), "r" (v) );    return 0;}/* * Signed division of double-word dividend. * IN:  Dividend=u[1]:u[0], Divisor=v * OUT: Return 1: #DE *      Return 0: Quotient=u[0], Remainder=u[1] * NB. We don't use idiv directly as it's moderately hard to work out *     ahead of time whether it will #DE, which we cannot allow to happen. */static int idiv_dbl(unsigned long u[2], unsigned long v){    int negu = (long)u[1] < 0, negv = (long)v < 0;    /* u = abs(u) */    if ( negu )    {        u[1] = ~u[1];        if ( (u[0] = -u[0]) == 0 )            u[1]++;    }    /* abs(u) / abs(v) */    if ( div_dbl(u, negv ? -v : v) )        return 1;    /* Remainder has same sign as dividend. It cannot overflow. */    if ( negu )        u[1] = -u[1];    /* Quotient is overflowed if sign bit is set. */    if ( negu ^ negv )    {        if ( (long)u[0] >= 0 )            u[0] = -u[0];        else if ( (u[0] << 1) != 0 ) /* == 0x80...0 is okay */            return 1;    }    else if ( (long)u[0] < 0 )        return 1;    return 0;}static inttest_cc(    unsigned int condition, unsigned int flags){    int rc = 0;    switch ( (condition & 15) >> 1 )    {    case 0: /* o */        rc |= (flags & EFLG_OF);        break;    case 1: /* b/c/nae */        rc |= (flags & EFLG_CF);        break;    case 2: /* z/e */        rc |= (flags & EFLG_ZF);        break;    case 3: /* be/na */        rc |= (flags & (EFLG_CF|EFLG_ZF));        break;    case 4: /* s */        rc |= (flags & EFLG_SF);        break;    case 5: /* p/pe */        rc |= (flags & EFLG_PF);        break;    case 7: /* le/ng */        rc |= (flags & EFLG_ZF);        /* fall through */    case 6: /* l/nge */        rc |= (!(flags & EFLG_SF) != !(flags & EFLG_OF));        break;    }    /* Odd condition identifiers (lsb == 1) have inverted sense. */    return (!!rc ^ (condition & 1));}static intget_cpl(    struct x86_emulate_ctxt *ctxt,    struct x86_emulate_ops  *ops){    struct segment_register reg;    if ( ctxt->regs->eflags & EFLG_VM )        return 3;    if ( (ops->read_segment == NULL) ||         ops->read_segment(x86_seg_ss, &reg, ctxt) )        return -1;    return reg.attr.fields.dpl;}static int_mode_iopl(    struct x86_emulate_ctxt *ctxt,    struct x86_emulate_ops  *ops){    int cpl = get_cpl(ctxt, ops);    if ( cpl == -1 )        return -1;    return (cpl <= ((ctxt->regs->eflags >> 12) & 3));}#define mode_ring0() ({                         \    int _cpl = get_cpl(ctxt, ops);              \    fail_if(_cpl < 0);                          \    (_cpl == 0);                                \})#define mode_iopl() ({                          \    int _iopl = _mode_iopl(ctxt, ops);          \    fail_if(_iopl < 0);                         \    _iopl;                                      \})static int ioport_access_check(    unsigned int first_port,    unsigned int bytes,    struct x86_emulate_ctxt *ctxt,    struct x86_emulate_ops *ops){    unsigned long iobmp;    struct segment_register tr;    int rc = X86EMUL_OKAY;    if ( !(ctxt->regs->eflags & EFLG_VM) && mode_iopl() )        return X86EMUL_OKAY;    fail_if(ops->read_segment == NULL);    if ( (rc = ops->read_segment(x86_seg_tr, &tr, ctxt)) != 0 )        return rc;    /* Ensure that the TSS is valid and has an io-bitmap-offset field. */    if ( !tr.attr.fields.p ||         ((tr.attr.fields.type & 0xd) != 0x9) ||         (tr.limit < 0x67) )        goto raise_exception;    if ( (rc = read_ulong(x86_seg_none, tr.base + 0x66,                          &iobmp, 2, ctxt, ops)) )        return rc;    /* Ensure TSS includes two bytes including byte containing first port. */    iobmp += first_port / 8;    if ( tr.limit <= iobmp )        goto raise_exception;    if ( (rc = read_ulong(x86_seg_none, tr.base + iobmp,                          &iobmp, 2, ctxt, ops)) )        return rc;    if ( (iobmp & (((1<<bytes)-1) << (first_port&7))) != 0 )        goto raise_exception; done:    return rc; raise_exception:    fail_if(ops->inject_hw_exception == NULL);    return ops->inject_hw_exception(EXC_GP, 0, ctxt) ? : X86EMUL_EXCEPTION;}static intin_realmode(    struct x86_emulate_ctxt *ctxt,    struct x86_emulate_ops  *ops){    unsigned long cr0;    int rc;    if ( ops->read_cr == NULL )        return 0;    rc = ops->read_cr(0, &cr0, ctxt);    return (!rc && !(cr0 & CR0_PE));}static intin_protmode(    struct x86_emulate_ctxt *ctxt,    struct x86_emulate_ops  *ops){    return !(in_realmode(ctxt, ops) || (ctxt->regs->eflags & EFLG_VM));}static intrealmode_load_seg(    enum x86_segment seg,    uint16_t sel,    struct x86_emulate_ctxt *ctxt,    struct x86_emulate_ops *ops){    struct segment_register reg;    int rc;    if ( (rc = ops->read_segment(seg, &reg, ctxt)) != 0 )        return rc;    reg.sel  = sel;    reg.base = (uint32_t)sel << 4;    return ops->write_segment(seg, &reg, ctxt);}static intprotmode_load_seg(    enum x86_segment seg,    uint16_t sel,    struct x86_emulate_ctxt *ctxt,    struct x86_emulate_ops *ops){    struct segment_register desctab, ss, segr;    struct { uint32_t a, b; } desc;    unsigned long val;    uint8_t dpl, rpl, cpl;    uint32_t new_desc_b;    int rc, fault_type = EXC_TS;    /* NULL selector? */    if ( (sel & 0xfffc) == 0 )    {        if ( (seg == x86_seg_cs) || (seg == x86_seg_ss) )            goto raise_exn;        memset(&segr, 0, sizeof(segr));        return ops->write_segment(seg, &segr, ctxt);    }    /* LDT descriptor must be in the GDT. */    if ( (seg == x86_seg_ldtr) && (sel & 4) )        goto raise_exn;    if ( (rc = ops->read_segment(x86_seg_ss, &ss, ctxt)) ||         (rc = ops->read_segment((sel & 4) ? x86_seg_ldtr : x86_seg_gdtr,                                 &desctab, ctxt)) )        return rc;    /* Check against descriptor table limit. */    if ( ((sel & 0xfff8) + 7) > desctab.limit )        goto raise_exn;    do {        if ( (rc = read_ulong(x86_seg_none, desctab.base + (sel & 0xfff8),                              &val, 4, ctxt, ops)) )            return rc;        desc.a = val;        if ( (rc = read_ulong(x86_seg_none, desctab.base + (sel & 0xfff8) + 4,                              &val, 4, ctxt, ops)) )            return rc;        desc.b = val;        /* Segment present in memory? */        if ( !(desc.b & (1u<<15)) )        {            fault_type = EXC_NP;            goto raise_exn;        }        /* LDT descriptor is a system segment. All others are code/data. */        if ( (desc.b & (1u<<12)) == ((seg == x86_seg_ldtr) << 12) )            goto raise_exn;        dpl = (desc.b >> 13) & 3;        rpl = sel & 3;        cpl = ss.attr.fields.dpl;        switch ( seg )        {        case x86_seg_cs:            /* Code segment? */            if ( !(desc.b & (1u<<11)) )                goto raise_exn;            /* Non-conforming segment: check DPL against RPL. */            if ( ((desc.b & (6u<<9)) != (6u<<9)) && (dpl != rpl) )                goto raise_exn;            break;        case x86_seg_ss:            /* Writable data segment? */            if ( (desc.b & (5u<<9)) != (1u<<9) )                goto raise_exn;            if ( (dpl != cpl) || (dpl != rpl) )                goto raise_exn;            break;        case x86_seg_ldtr:            /* LDT system segment? */            if ( (desc.b & (15u<<8)) != (2u<<8) )                goto raise_exn;            goto skip_accessed_flag;        default:            /* Readable code or data segment? */            if ( (desc.b & (5u<<9)) == (4u<<9) )                goto raise_exn;            /* Non-conforming segment: check DPL against RPL and CPL. */            if ( ((desc.b & (6u<<9)) != (6u<<9)) &&                 ((dpl < cpl) || (dpl < rpl)) )                goto raise_exn;            break;        }        /* Ensure Accessed flag is set. */        new_desc_b = desc.b | 0x100;        rc = ((desc.b & 0x100) ? X86EMUL_OKAY :              ops->cmpxchg(                  x86_seg_none, desctab.base + (sel & 0xfff8) + 4,                  &desc.b, &new_desc_b, 4, ctxt));    } while ( rc == X86EMUL_CMPXCHG_FAILED );    if ( rc )        return rc;    /* Force the Accessed flag in our local copy. */    desc.b |= 0x100; skip_accessed_flag:    segr.base = (((desc.b <<  0) & 0xff000000u) |                 ((desc.b << 16) & 0x00ff0000u) |                 ((desc.a >> 16) & 0x0000ffffu));    segr.attr.bytes = (((desc.b >>  8) & 0x00ffu) |                       ((desc.b >> 12) & 0x0f00u));    segr.limit = (desc.b & 0x000f0000u) | (desc.a & 0x0000ffffu);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?