⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 traps.c

📁 xen 3.2.2 源码
💻 C
📖 第 1 页 / 共 5 页
字号:
         __get_user(desc, pdesc) )        return 0;    *sel = (desc.a >> 16) & 0x0000fffc;    *off = (desc.a & 0x0000ffff) | (desc.b & 0xffff0000);    *ar = desc.b & 0x0000ffff;    /*     * check_descriptor() clears the DPL field and stores the     * guest requested DPL in the selector's RPL field.     */    if ( *ar & _SEGMENT_DPL )        return 0;    *ar |= (desc.a >> (16 - 13)) & _SEGMENT_DPL;    if ( !is_pv_32bit_vcpu(v) )    {        if ( (*ar & 0x1f00) != 0x0c00 ||             (gate_sel >= FIRST_RESERVED_GDT_BYTE - 8 && !(gate_sel & 4)) ||             __get_user(desc, pdesc + 1) ||             (desc.b & 0x1f00) )            return 0;        *off |= (unsigned long)desc.a << 32;        return 1;    }    switch ( *ar & 0x1f00 )    {    case 0x0400:        *off &= 0xffff;        break;    case 0x0c00:        break;    default:        return 0;    }    return 1;}#endif/* Has the guest requested sufficient permission for this I/O access? */static inline int guest_io_okay(    unsigned int port, unsigned int bytes,    struct vcpu *v, struct cpu_user_regs *regs){#if defined(__x86_64__)    /* If in user mode, switch to kernel mode just to read I/O bitmap. */    int user_mode = !(v->arch.flags & TF_kernel_mode);#define TOGGLE_MODE() if ( user_mode ) toggle_guest_mode(v)#elif defined(__i386__)#define TOGGLE_MODE() ((void)0)#endif    if ( !vm86_mode(regs) &&         (v->arch.iopl >= (guest_kernel_mode(v, regs) ? 1 : 3)) )        return 1;    if ( v->arch.iobmp_limit > (port + bytes) )    {        union { uint8_t bytes[2]; uint16_t mask; } x;        /*         * Grab permission bytes from guest space. Inaccessible bytes are         * read as 0xff (no access allowed).         */        TOGGLE_MODE();        switch ( __copy_from_guest_offset(x.bytes, v->arch.iobmp,                                          port>>3, 2) )        {        default: x.bytes[0] = ~0;        case 1:  x.bytes[1] = ~0;        case 0:  break;        }        TOGGLE_MODE();        if ( (x.mask & (((1<<bytes)-1) << (port&7))) == 0 )            return 1;    }    return 0;}/* Has the administrator granted sufficient permission for this I/O access? */static inline int admin_io_okay(    unsigned int port, unsigned int bytes,    struct vcpu *v, struct cpu_user_regs *regs){    return ioports_access_permitted(v->domain, port, port + bytes - 1);}#define guest_inb_okay(_p, _d, _r) admin_io_okay(_p, 1, _d, _r)#define guest_inw_okay(_p, _d, _r) admin_io_okay(_p, 2, _d, _r)#define guest_inl_okay(_p, _d, _r) admin_io_okay(_p, 4, _d, _r)#define guest_outb_okay(_p, _d, _r) admin_io_okay(_p, 1, _d, _r)#define guest_outw_okay(_p, _d, _r) admin_io_okay(_p, 2, _d, _r)#define guest_outl_okay(_p, _d, _r) admin_io_okay(_p, 4, _d, _r)/* I/O emulation support. Helper routines for, and type of, the stack stub.*/void host_to_guest_gpr_switch(struct cpu_user_regs *)    __attribute__((__regparm__(1)));unsigned long guest_to_host_gpr_switch(unsigned long)    __attribute__((__regparm__(1)));void (*pv_post_outb_hook)(unsigned int port, u8 value);/* Instruction fetch with error handling. */#define insn_fetch(type, base, eip, limit)                                  \({  unsigned long _rc, _ptr = (base) + (eip);                               \    type _x;                                                                \    if ( ad_default < 8 )                                                   \        _ptr = (unsigned int)_ptr;                                          \    if ( (limit) < sizeof(_x) - 1 || (eip) > (limit) - (sizeof(_x) - 1) )   \        goto fail;                                                          \    if ( (_rc = copy_from_user(&_x, (type *)_ptr, sizeof(_x))) != 0 )       \    {                                                                       \        propagate_page_fault(_ptr + sizeof(_x) - _rc, 0);                   \        goto skip;                                                          \    }                                                                       \    (eip) += sizeof(_x); _x; })#if defined(CONFIG_X86_32)# define read_sreg(regs, sr) ((regs)->sr)#elif defined(CONFIG_X86_64)# define read_sreg(regs, sr) read_segment_register(sr)#endifstatic int emulate_privileged_op(struct cpu_user_regs *regs){    struct vcpu *v = current;    unsigned long *reg, eip = regs->eip, res;    u8 opcode, modrm_reg = 0, modrm_rm = 0, rep_prefix = 0, lock = 0, rex = 0;    enum { lm_seg_none, lm_seg_fs, lm_seg_gs } lm_ovr = lm_seg_none;    unsigned int port, i, data_sel, ar, data, rc, bpmatch = 0;    unsigned int op_bytes, op_default, ad_bytes, ad_default;#define rd_ad(reg) (ad_bytes >= sizeof(regs->reg) \                    ? regs->reg \                    : ad_bytes == 4 \                      ? (u32)regs->reg \                      : (u16)regs->reg)#define wr_ad(reg, val) (ad_bytes >= sizeof(regs->reg) \                         ? regs->reg = (val) \                         : ad_bytes == 4 \                           ? (*(u32 *)&regs->reg = (val)) \                           : (*(u16 *)&regs->reg = (val)))    unsigned long code_base, code_limit;    char io_emul_stub[32];    void (*io_emul)(struct cpu_user_regs *) __attribute__((__regparm__(1)));    u32 l, h, eax, edx;    if ( !read_descriptor(regs->cs, v, regs,                          &code_base, &code_limit, &ar,                          _SEGMENT_CODE|_SEGMENT_S|_SEGMENT_DPL|_SEGMENT_P) )        goto fail;    op_default = op_bytes = (ar & (_SEGMENT_L|_SEGMENT_DB)) ? 4 : 2;    ad_default = ad_bytes = (ar & _SEGMENT_L) ? 8 : op_default;    if ( !(ar & _SEGMENT_S) ||         !(ar & _SEGMENT_P) ||         !(ar & _SEGMENT_CODE) )        goto fail;    /* emulating only opcodes not allowing SS to be default */    data_sel = read_sreg(regs, ds);    /* Legacy prefixes. */    for ( i = 0; i < 8; i++, rex == opcode || (rex = 0) )    {        switch ( opcode = insn_fetch(u8, code_base, eip, code_limit) )        {        case 0x66: /* operand-size override */            op_bytes = op_default ^ 6; /* switch between 2/4 bytes */            continue;        case 0x67: /* address-size override */            ad_bytes = ad_default != 4 ? 4 : 2; /* switch to 2/4 bytes */            continue;        case 0x2e: /* CS override */            data_sel = regs->cs;            continue;        case 0x3e: /* DS override */            data_sel = read_sreg(regs, ds);            continue;        case 0x26: /* ES override */            data_sel = read_sreg(regs, es);            continue;        case 0x64: /* FS override */            data_sel = read_sreg(regs, fs);            lm_ovr = lm_seg_fs;            continue;        case 0x65: /* GS override */            data_sel = read_sreg(regs, gs);            lm_ovr = lm_seg_gs;            continue;        case 0x36: /* SS override */            data_sel = regs->ss;            continue;        case 0xf0: /* LOCK */            lock = 1;            continue;        case 0xf2: /* REPNE/REPNZ */        case 0xf3: /* REP/REPE/REPZ */            rep_prefix = 1;            continue;        default:            if ( (ar & _SEGMENT_L) && (opcode & 0xf0) == 0x40 )            {                rex = opcode;                continue;            }            break;        }        break;    }    /* REX prefix. */    if ( rex & 8 ) /* REX.W */        op_bytes = 4; /* emulating only opcodes not supporting 64-bit operands */    modrm_reg = (rex & 4) << 1;  /* REX.R */    /* REX.X does not need to be decoded. */    modrm_rm  = (rex & 1) << 3;  /* REX.B */    if ( opcode == 0x0f )        goto twobyte_opcode;        if ( lock )        goto fail;    /* Input/Output String instructions. */    if ( (opcode >= 0x6c) && (opcode <= 0x6f) )    {        unsigned long data_base, data_limit;        if ( rep_prefix && (rd_ad(ecx) == 0) )            goto done;        if ( !(opcode & 2) )        {            data_sel = read_sreg(regs, es);            lm_ovr = lm_seg_none;        }        if ( !(ar & _SEGMENT_L) )        {            if ( !read_descriptor(data_sel, v, regs,                                  &data_base, &data_limit, &ar,                                  _SEGMENT_WR|_SEGMENT_S|_SEGMENT_DPL|_SEGMENT_P) )                goto fail;            if ( !(ar & _SEGMENT_S) ||                 !(ar & _SEGMENT_P) ||                 (opcode & 2 ?                  (ar & _SEGMENT_CODE) && !(ar & _SEGMENT_WR) :                  (ar & _SEGMENT_CODE) || !(ar & _SEGMENT_WR)) )                goto fail;        }#ifdef CONFIG_X86_64        else        {            if ( lm_ovr == lm_seg_none || data_sel < 4 )            {                switch ( lm_ovr )                {                case lm_seg_none:                    data_base = 0UL;                    break;                case lm_seg_fs:                    data_base = v->arch.guest_context.fs_base;                    break;                case lm_seg_gs:                    if ( guest_kernel_mode(v, regs) )                        data_base = v->arch.guest_context.gs_base_kernel;                    else                        data_base = v->arch.guest_context.gs_base_user;                    break;                }            }            else                read_descriptor(data_sel, v, regs,                                &data_base, &data_limit, &ar,                                0);            data_limit = ~0UL;            ar = _SEGMENT_WR|_SEGMENT_S|_SEGMENT_DPL|_SEGMENT_P;        }#endif        port = (u16)regs->edx;    continue_io_string:        switch ( opcode )        {        case 0x6c: /* INSB */            op_bytes = 1;        case 0x6d: /* INSW/INSL */            if ( data_limit < op_bytes - 1 ||                 rd_ad(edi) > data_limit - (op_bytes - 1) ||                 !guest_io_okay(port, op_bytes, v, regs) )                goto fail;            switch ( op_bytes )            {            case 1:                /* emulate PIT counter 2 */                data = (u8)(guest_inb_okay(port, v, regs) ? inb(port) :                        ((port == 0x42 || port == 0x43 || port == 0x61) ?                       pv_pit_handler(port, 0, 0) : ~0));                 break;            case 2:                data = (u16)(guest_inw_okay(port, v, regs) ? inw(port) : ~0);                break;            case 4:                data = (u32)(guest_inl_okay(port, v, regs) ? inl(port) : ~0);                break;            }            if ( (rc = copy_to_user((void *)data_base + rd_ad(edi), &data, op_bytes)) != 0 )            {                propagate_page_fault(data_base + rd_ad(edi) + op_bytes - rc,                                     PFEC_write_access);                return EXCRET_fault_fixed;            }            wr_ad(edi, regs->edi + (int)((regs->eflags & EF_DF) ? -op_bytes : op_bytes));            break;        case 0x6e: /* OUTSB */            op_bytes = 1;        case 0x6f: /* OUTSW/OUTSL */            if ( data_limit < op_bytes - 1 ||                 rd_ad(esi) > data_limit - (op_bytes - 1) ||                 !guest_io_okay(port, op_bytes, v, regs) )                goto fail;            rc = copy_from_user(&data, (void *)data_base + rd_ad(esi), op_bytes);            if ( rc != 0 )            {                propagate_page_fault(data_base + rd_ad(esi) + op_bytes - rc, 0);                return EXCRET_fault_fixed;            }            switch ( op_bytes )            {            case 1:                if ( guest_outb_okay(port, v, regs) )                {                    outb((u8)data, port);                    if ( pv_post_outb_hook )                        pv_post_outb_hook(port, data);                }                else if ( port == 0x42 || port == 0x43 || port == 0x61 )                    pv_pit_handler(port, data, 1);                break;            case 2:                if ( guest_outw_okay(port, v, regs) )                    outw((u16)data, port);                break;            case 4:                if ( guest_outl_okay(port, v, regs) )                    outl((u32)data, port);                break;            }            wr_ad(esi, regs->esi + (int)((regs->eflags & EF_DF) ? -op_bytes : op_bytes));            break;        }        bpmatch = check_guest_io_breakpoint(v, port, op_bytes);        if ( rep_prefix && (wr_ad(ecx, regs->ecx - 1) != 0) )        {            if ( !bpmatch && !hypercall_preempt_check() )                goto continue_io_string;            eip = regs->eip;        }        goto done;    }    /*     * Very likely to be an I/O instruction (IN/OUT).     * Build an on-stack stub to execute the instruction with full guest     * GPR context. This is needed for some systems which (ab)use IN/OUT     * to communicate with BIOS code in system-management mode.     */#ifdef __x86_64__    /* movq $host_to_guest_gpr_switch,%rcx */    io_emul_stub[0] = 0x48;    io_emul_stub[1] = 0xb9;    *(void **)&io_emul_stub[2] = (void *)host_to_guest_gpr_switch;    /* callq *%rcx */    io_emul_stub[10] = 0xff;    io_emul_stub[11] = 0xd1;#else    /* call host_to_guest_gpr_switch */    io_emul_stub[0] = 0xe8;    *(s32 *)&io_emul_stub[1] =        (char *)host_to_guest_gpr_switch - &io_emul_stub[5];    /* 7 x nop */    memset(&io_emul_stub[5], 0x90, 7);#endif    /* data16 or nop */    io_emul_stub[12] = (op_bytes != 2) ? 0x90 : 0x66;    /* <io-access opcode> */    io_emul_stub[13] = opcode;    /* imm8 or nop */    io_emul_stub[14] = 0x90;    /* ret (jumps to guest_to_host_gpr_switch) */    io_emul_stub[15] = 0xc3;    /* Handy function-typed pointer to the stub. */    io_emul = (void *)io_emul_stub;    if ( ioemul_handle_quirk )        ioemul_handle_quirk(opcode, &io_emul_stub[12], regs);    /* I/O Port and Interrupt Flag instructions. */    switch ( opcode )    {    case 0xe4: /* IN imm8,%al */        op_bytes = 1;    case 0xe5: /* IN imm8,%eax */        port = insn_fetch(u8, code_base, eip, code_limit);        io_emul_stub[14] = port; /* imm8 */    exec_in:        if ( !guest_io_okay(port, op_bytes, v, regs) )            goto fail;        switch ( op_bytes )        {        case 1:            if ( guest_inb_okay(port, v, regs) )                io_emul(regs);            else if ( port == 0x42 || port == 0x43 || port == 0x61 )            {                regs->eax &= ~0xffUL;                regs->eax |= pv_pit_handler(port, 0, 0);            }             else                regs->eax |= (u8)~0;            break;

⌨️ 快捷键说明

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