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

📄 svm.c

📁 xen 3.2.2 源码
💻 C
📖 第 1 页 / 共 5 页
字号:
                        *addr - (*count - 1) * size <= seg->limit)                        *count = (*addr - seg->limit - 1) / size + 1;                }            }            ASSERT(*count);        }        *addr += seg->base;    }#ifdef __x86_64__    else    {        if (seg == &vmcb->fs || seg == &vmcb->gs)            *addr += seg->base;        if (!is_canonical_address(*addr) ||            !is_canonical_address(*addr + size - 1))        {            svm_inject_exception(TRAP_gp_fault, 0, 0);            return 0;        }        if (*count > (1UL << 48) / size)            *count = (1UL << 48) / size;        if (!(regs->eflags & EF_DF))        {            if (*addr + *count * size - 1 < *addr ||                !is_canonical_address(*addr + *count * size - 1))                *count = (*addr & ~((1UL << 48) - 1)) / size;        }        else        {            if ((*count - 1) * size > *addr ||                !is_canonical_address(*addr + (*count - 1) * size))                *count = (*addr & ~((1UL << 48) - 1)) / size + 1;        }        ASSERT(*count);    }#endif    return 1;}static void svm_io_instruction(struct vcpu *v){    struct cpu_user_regs *regs;    struct hvm_io_op *pio_opp;    unsigned int port;    unsigned int size, dir, df;    ioio_info_t info;    struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;    pio_opp = &current->arch.hvm_vcpu.io_op;    pio_opp->instr = INSTR_PIO;    pio_opp->flags = 0;    regs = &pio_opp->io_context;    /* Copy current guest state into io instruction state structure. */    memcpy(regs, guest_cpu_user_regs(), HVM_CONTEXT_STACK_BYTES);    info.bytes = vmcb->exitinfo1;    port = info.fields.port; /* port used to be addr */    dir = info.fields.type; /* direction */     df = regs->eflags & X86_EFLAGS_DF ? 1 : 0;    if (info.fields.sz32)         size = 4;    else if (info.fields.sz16)        size = 2;    else         size = 1;    if (dir==IOREQ_READ)        HVMTRACE_2D(IO_READ,  v, port, size);    else        HVMTRACE_3D(IO_WRITE, v, port, size, regs->eax);    HVM_DBG_LOG(DBG_LEVEL_IO,                 "svm_io_instruction: port 0x%x eip=%x:%"PRIx64", "                "exit_qualification = %"PRIx64,                port, vmcb->cs.sel, (uint64_t)regs->eip, info.bytes);    /* string instruction */    if (info.fields.str)    {         unsigned long addr, count;        paddr_t paddr;        unsigned long gfn;        uint32_t pfec;        int sign = regs->eflags & X86_EFLAGS_DF ? -1 : 1;        if (!svm_get_io_address(v, regs, size, info, &count, &addr))        {            /* We failed to get a valid address, so don't do the IO operation -             * it would just get worse if we do! Hopefully the guest is handing             * gp-faults...              */            return;        }        /* "rep" prefix */        if (info.fields.rep)         {            pio_opp->flags |= REPZ;        }        /* Translate the address to a physical address */        pfec = PFEC_page_present;        if ( dir == IOREQ_READ ) /* Read from PIO --> write to RAM */            pfec |= PFEC_write_access;        if ( vmcb->cpl == 3 )            pfec |= PFEC_user_mode;        gfn = paging_gva_to_gfn(v, addr, &pfec);        if ( gfn == INVALID_GFN )         {            /* The guest does not have the RAM address mapped.              * Need to send in a page fault */            svm_inject_exception(TRAP_page_fault, pfec, addr);            return;        }        paddr = (paddr_t)gfn << PAGE_SHIFT | (addr & ~PAGE_MASK);        /*         * Handle string pio instructions that cross pages or that         * are unaligned. See the comments in hvm_platform.c/handle_mmio()         */        if ((addr & PAGE_MASK) != ((addr + size - 1) & PAGE_MASK))        {            unsigned long value = 0;            pio_opp->flags |= OVERLAP;            pio_opp->addr = addr;            if (dir == IOREQ_WRITE)   /* OUTS */            {                if ( hvm_paging_enabled(current) )                {                    int rv = hvm_copy_from_guest_virt(&value, addr, size);                    if ( rv == HVMCOPY_bad_gva_to_gfn )                        return; /* exception already injected */                }                else                    (void)hvm_copy_from_guest_phys(&value, addr, size);            }            else /* dir != IOREQ_WRITE */                /* Remember where to write the result, as a *VA*.                 * Must be a VA so we can handle the page overlap                  * correctly in hvm_pio_assist() */                pio_opp->addr = addr;            if (count == 1)                regs->eip = vmcb->exitinfo2;            send_pio_req(port, 1, size, value, dir, df, 0);        }         else         {            unsigned long last_addr = sign > 0 ? addr + count * size - 1                                               : addr - (count - 1) * size;            if ((addr & PAGE_MASK) != (last_addr & PAGE_MASK))            {                if (sign > 0)                    count = (PAGE_SIZE - (addr & ~PAGE_MASK)) / size;                else                    count = (addr & ~PAGE_MASK) / size + 1;            }            else                    regs->eip = vmcb->exitinfo2;            send_pio_req(port, count, size, paddr, dir, df, 1);        }    }     else     {        /*          * On SVM, the RIP of the intruction following the IN/OUT is saved in         * ExitInfo2         */        regs->eip = vmcb->exitinfo2;        if (port == 0xe9 && dir == IOREQ_WRITE && size == 1)             hvm_print_line(v, regs->eax); /* guest debug output */            send_pio_req(port, 1, size, regs->eax, dir, df, 0);    }}static void mov_from_cr(int cr, int gp, struct cpu_user_regs *regs){    unsigned long value = 0;    struct vcpu *v = current;    struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;    switch ( cr )    {    case 0:        value = v->arch.hvm_vcpu.guest_cr[0];        break;    case 3:        value = (unsigned long)v->arch.hvm_vcpu.guest_cr[3];        break;    case 4:        value = (unsigned long)v->arch.hvm_vcpu.guest_cr[4];        break;    default:        gdprintk(XENLOG_ERR, "invalid cr: %d\n", cr);        domain_crash(v->domain);        return;    }    HVMTRACE_2D(CR_READ, v, cr, value);    set_reg(gp, value, regs, vmcb);    HVM_DBG_LOG(DBG_LEVEL_VMMU, "mov_from_cr: CR%d, value = %lx", cr, value);}static int mov_to_cr(int gpreg, int cr, struct cpu_user_regs *regs){    unsigned long value;    struct vcpu *v = current;    struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;    value = get_reg(gpreg, regs, vmcb);    HVMTRACE_2D(CR_WRITE, v, cr, value);    HVM_DBG_LOG(DBG_LEVEL_1, "mov_to_cr: CR%d, value = %lx, current = %p",                cr, value, v);    switch ( cr )    {    case 0:         return hvm_set_cr0(value);    case 3:        return hvm_set_cr3(value);    case 4:        return hvm_set_cr4(value);    default:        gdprintk(XENLOG_ERR, "invalid cr: %d\n", cr);        domain_crash(v->domain);        return 0;    }    return 1;}static void svm_cr_access(    struct vcpu *v, unsigned int cr, unsigned int type,    struct cpu_user_regs *regs){    struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;    int inst_len = 0;    int index,addr_size,i;    unsigned int gpreg,offset;    unsigned long value,addr;    u8 buffer[MAX_INST_LEN];       u8 prefix = 0;    u8 modrm;    enum x86_segment seg;    int result = 1;    enum instruction_index list_a[] = {INSTR_MOV2CR, INSTR_CLTS, INSTR_LMSW};    enum instruction_index list_b[] = {INSTR_MOVCR2, INSTR_SMSW};    enum instruction_index match;    if ( type == TYPE_MOV_TO_CR )    {        inst_len = __get_instruction_length_from_list(            v, list_a, ARRAY_SIZE(list_a), buffer, &match);    }    else /* type == TYPE_MOV_FROM_CR */    {        inst_len = __get_instruction_length_from_list(            v, list_b, ARRAY_SIZE(list_b), buffer, &match);    }    if ( inst_len == 0 )        return;    /* get index to first actual instruction byte - as we will need to know        where the prefix lives later on */    index = skip_prefix_bytes(buffer, sizeof(buffer));    /* Check for REX prefix - it's ALWAYS the last byte of any prefix bytes */    if (index > 0 && (buffer[index-1] & 0xF0) == 0x40)        prefix = buffer[index-1];    HVM_DBG_LOG(DBG_LEVEL_1, "eip = %lx", (unsigned long)regs->eip);    switch ( match )    {    case INSTR_MOV2CR:        gpreg = decode_src_reg(prefix, buffer[index+2]);        result = mov_to_cr(gpreg, cr, regs);        break;    case INSTR_MOVCR2:        gpreg = decode_src_reg(prefix, buffer[index+2]);        mov_from_cr(cr, gpreg, regs);        break;    case INSTR_CLTS:        v->arch.hvm_vcpu.guest_cr[0] &= ~X86_CR0_TS;        svm_update_guest_cr(v, 0);        HVMTRACE_0D(CLTS, current);        break;    case INSTR_LMSW:        gpreg = decode_src_reg(prefix, buffer[index+2]);        value = get_reg(gpreg, regs, vmcb) & 0xF;        value = (v->arch.hvm_vcpu.guest_cr[0] & ~0xF) | value;        result = hvm_set_cr0(value);        HVMTRACE_1D(LMSW, current, value);        break;    case INSTR_SMSW:        value = v->arch.hvm_vcpu.guest_cr[0] & 0xFFFF;        modrm = buffer[index+2];        addr_size = svm_guest_x86_mode(v);        if ( addr_size < 2 )            addr_size = 2;        if ( likely((modrm & 0xC0) >> 6 == 3) )        {            gpreg = decode_src_reg(prefix, modrm);            set_reg(gpreg, value, regs, vmcb);        }        /*         * For now, only implement decode of the offset mode, since that's the         * only mode observed in a real-world OS. This code is also making the         * assumption that we'll never hit this code in long mode.         */        else if ( (modrm == 0x26) || (modrm == 0x25) )        {               seg = x86_seg_ds;            i = index;            /* Segment or address size overrides? */            while ( i-- )            {                switch ( buffer[i] )                {                   case 0x26: seg = x86_seg_es; break;                   case 0x2e: seg = x86_seg_cs; break;                   case 0x36: seg = x86_seg_ss; break;                   case 0x64: seg = x86_seg_fs; break;                   case 0x65: seg = x86_seg_gs; break;                   case 0x67: addr_size ^= 6;   break;                }            }            /* Bail unless this really is a seg_base + offset case */            if ( ((modrm == 0x26) && (addr_size == 4)) ||                 ((modrm == 0x25) && (addr_size == 2)) )            {                gdprintk(XENLOG_ERR, "SMSW emulation at guest address: "                         "%lx failed due to unhandled addressing mode."                         "ModRM byte was: %x \n", svm_rip2pointer(v), modrm);                domain_crash(v->domain);            }            inst_len += addr_size;            offset = *(( unsigned int *) ( void *) &buffer[index + 3]);            offset = ( addr_size == 4 ) ? offset : ( offset & 0xFFFF );            addr = hvm_get_segment_base(v, seg);            addr += offset;            result = (hvm_copy_to_guest_virt(addr, &value, 2)                      != HVMCOPY_bad_gva_to_gfn);        }        else        {           gdprintk(XENLOG_ERR, "SMSW emulation at guest address: %lx "                    "failed due to unhandled addressing mode!"                    "ModRM byte was: %x \n", svm_rip2pointer(v), modrm);           domain_crash(v->domain);        }        break;    default:        BUG();    }    if ( result )        __update_guest_eip(regs, inst_len);}static void svm_do_msr_access(    struct vcpu *v, struct cpu_user_regs *regs){    struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;    int  inst_len;    u64 msr_content=0;    u32 ecx = regs->ecx, eax, edx;    HVM_DBG_LOG(DBG_LEVEL_1, "ecx=%x, eax=%x, edx=%x, exitinfo = %lx",                ecx, (u32)regs->eax, (u32)regs->edx,                (unsigned long)vmcb->exitinfo1);    /* is it a read? */    if (vmcb->exitinfo1 == 0)    {        switch (ecx) {        case MSR_IA32_TSC:            msr_content = hvm_get_guest_time(v);            break;        case MSR_IA32_APICBASE:            msr_content = vcpu_vlapic(v)->hw.apic_base_msr;            break;        case MSR_EFER:            msr_content = v->arch.hvm_vcpu.guest_efer;            break;        case MSR_IA32_MC4_MISC: /* Threshold register */        case MSR_F10_MC4_MISC1 ... MSR_F10_MC4_MISC3:            /*             * MCA/MCE: We report that the threshold register is unavailable             * for OS use (locked by the BIOS).             */            msr_content = 1ULL << 61; /* MC4_MISC.Locked */            break;        case MSR_IA32_EBC_FREQUENCY_ID:            /*             * This Intel-only register may be accessed if this HVM guest             * has been migrated from an Intel host. The value zero is not             * particularly meaningful, but at least avoids the guest crashing!             */            msr_content = 0;            break;        case MSR_K8_VM_HSAVE_PA:            svm_inject_exception(TRAP_gp_fault, 0, 0);            break;        case MSR_IA32_MCG_CAP:        case MSR_IA32_MCG_STATUS:        case MSR_IA32_MC0_STATUS:        case MSR_IA32_MC1_STATUS:        case MSR_IA32_MC2_STATUS:        case MSR_IA32_MC3_STATUS:        case MSR_IA32_MC4_STATUS:        case MSR_IA32_MC5_STATUS:            /* No point in letting the guest see real MCEs */            msr_content = 0;            break;        case MSR_IA32_DEBUGCTLMSR:

⌨️ 快捷键说明

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