Exemple #1
0
int handle_mmio(mmio_info_t *info)
{
    struct vcpu *v = current;
    int i;
    const struct mmio_handler *handler = NULL;
    const struct vmmio *vmmio = &v->domain->arch.vmmio;
    struct hsr_dabt dabt = info->dabt;
    struct cpu_user_regs *regs = guest_cpu_user_regs();
    register_t *r = select_user_reg(regs, dabt.reg);

    for ( i = 0; i < vmmio->num_entries; i++ )
    {
        handler = &vmmio->handlers[i];

        if ( (info->gpa >= handler->addr) &&
             (info->gpa < (handler->addr + handler->size)) )
            break;
    }

    if ( i == vmmio->num_entries )
        return 0;

    if ( info->dabt.write )
        return handler->ops->write(v, info, *r, handler->priv);
    else
        return handle_read(handler, v, info, r);
}
Exemple #2
0
void __trace_pv_page_fault(unsigned long addr, unsigned error_code)
{
    unsigned long eip = guest_cpu_user_regs()->eip;

    if ( is_pv_32bit_vcpu(current) )
    {
        struct __packed {
            u32 eip, addr, error_code;
        } d;

        d.eip = eip;
        d.addr = addr;
        d.error_code = error_code;
                
        __trace_var(TRC_PV_PAGE_FAULT, 1, sizeof(d), &d);
    }
    else
    {
        struct __packed {
            unsigned long eip, addr;
            u32 error_code;
        } d;
        unsigned event;

        d.eip = eip;
        d.addr = addr;
        d.error_code = error_code;
        event = TRC_PV_PAGE_FAULT;
        event |= TRC_64_FLAG;
        __trace_var(event, 1, sizeof(d), &d);
    }
}
Exemple #3
0
void __trace_hypercall_entry(void)
{
    struct cpu_user_regs *regs = guest_cpu_user_regs();
    unsigned long args[6];

    if ( is_pv_32bit_vcpu(current) )
    {
        args[0] = regs->ebx;
        args[1] = regs->ecx;
        args[2] = regs->edx;
        args[3] = regs->esi;
        args[4] = regs->edi;
        args[5] = regs->ebp;
    }
    else
    {
        args[0] = regs->rdi;
        args[1] = regs->rsi;
        args[2] = regs->rdx;
        args[3] = regs->r10;
        args[4] = regs->r8;
        args[5] = regs->r9;
    }

    __trace_hypercall(TRC_PV_HYPERCALL_V2, regs->eax, args);
}
Exemple #4
0
static unsigned long svm_rip2pointer(struct vcpu *v)
{
    struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
    unsigned long p = vmcb->cs.base + guest_cpu_user_regs()->eip;
    if ( !(vmcb->cs.attr.fields.l && hvm_long_mode_enabled(v)) )
        return (u32)p; /* mask to 32 bits */
    return p;
}
Exemple #5
0
unsigned long hypercall_create_continuation(
    unsigned int op, const char *format, ...)
{
    struct mc_state *mcs = &current->mc_state;
    struct cpu_user_regs *regs;
    const char *p = format;
    unsigned long arg, rc;
    unsigned int i;
    va_list args;

    /* All hypercalls take at least one argument */
    BUG_ON( !p || *p == '\0' );

    va_start(args, format);

    if ( test_bit(_MCSF_in_multicall, &mcs->flags) )
    {
        BUG(); /* XXX multicalls not implemented yet. */

        __set_bit(_MCSF_call_preempted, &mcs->flags);

        for ( i = 0; *p != '\0'; i++ )
            mcs->call.args[i] = next_arg(p, args);

        /* Return value gets written back to mcs->call.result */
        rc = mcs->call.result;
    }
    else
    {
        regs      = guest_cpu_user_regs();
        regs->r12 = op;

        /* Ensure the hypercall trap instruction is re-executed. */
        regs->pc -= 4;  /* re-execute 'hvc #XEN_HYPERCALL_TAG' */

        for ( i = 0; *p != '\0'; i++ )
        {
            arg = next_arg(p, args);

            switch ( i )
            {
            case 0: regs->r0 = arg; break;
            case 1: regs->r1 = arg; break;
            case 2: regs->r2 = arg; break;
            case 3: regs->r3 = arg; break;
            case 4: regs->r4 = arg; break;
            case 5: regs->r5 = arg; break;
            }
        }

        /* Return value gets written back to r0 */
        rc = regs->r0;
    }

    va_end(args);

    return rc;
}
Exemple #6
0
static void ns16550_poll(void *data)
{
    this_cpu(poll_port) = data;
#ifdef run_in_exception_handler
    run_in_exception_handler(__ns16550_poll);
#else
    __ns16550_poll(guest_cpu_user_regs());
#endif
}
Exemple #7
0
static int handle_write(const struct mmio_handler *handler, struct vcpu *v,
                        mmio_info_t *info)
{
    const struct hsr_dabt dabt = info->dabt;
    struct cpu_user_regs *regs = guest_cpu_user_regs();

    return handler->ops->write(v, info, get_user_reg(regs, dabt.reg),
                               handler->priv);
}
Exemple #8
0
unsigned long do_iret(void)
{
    struct cpu_user_regs *regs = guest_cpu_user_regs();
    struct iret_context iret_saved;
    struct vcpu *v = current;

    if ( unlikely(copy_from_user(&iret_saved, (void *)regs->rsp,
                                 sizeof(iret_saved))) )
    {
        gprintk(XENLOG_ERR,
                "Fault while reading IRET context from guest stack\n");
        goto exit_and_crash;
    }

    /* Returning to user mode? */
    if ( (iret_saved.cs & 3) == 3 )
    {
        if ( unlikely(pagetable_is_null(v->arch.guest_table_user)) )
        {
            gprintk(XENLOG_ERR,
                    "Guest switching to user mode with no user page tables\n");
            goto exit_and_crash;
        }
        toggle_guest_mode(v);
    }

    if ( VM_ASSIST(v->domain, architectural_iopl) )
        v->arch.pv_vcpu.iopl = iret_saved.rflags & X86_EFLAGS_IOPL;

    regs->rip    = iret_saved.rip;
    regs->cs     = iret_saved.cs | 3; /* force guest privilege */
    regs->rflags = ((iret_saved.rflags & ~(X86_EFLAGS_IOPL|X86_EFLAGS_VM))
                    | X86_EFLAGS_IF);
    regs->rsp    = iret_saved.rsp;
    regs->ss     = iret_saved.ss | 3; /* force guest privilege */

    if ( !(iret_saved.flags & VGCF_in_syscall) )
    {
        regs->entry_vector &= ~TRAP_syscall;
        regs->r11 = iret_saved.r11;
        regs->rcx = iret_saved.rcx;
    }

    /* Restore upcall mask from supplied EFLAGS.IF. */
    vcpu_info(v, evtchn_upcall_mask) = !(iret_saved.rflags & X86_EFLAGS_IF);

    async_exception_cleanup(v);

    /* Saved %rax gets written back to regs->rax in entry.S. */
    return iret_saved.rax;

 exit_and_crash:
    domain_crash(v->domain);
    return 0;
}
Exemple #9
0
void hypercall_cancel_continuation(void)
{
    struct cpu_user_regs *regs = guest_cpu_user_regs();
    struct mc_state *mcs = &current->mc_state;

    if ( test_bit(_MCSF_in_multicall, &mcs->flags) )
    {
        __clear_bit(_MCSF_call_preempted, &mcs->flags);
    }
    else
    {
        regs->pc += 4; /* undo re-execute 'hvc #XEN_HYPERCALL_TAG' */
    }
}
Exemple #10
0
static int vuart_mmio_write(struct vcpu *v, mmio_info_t *info, void *priv)
{
    struct domain *d = v->domain;
    struct hsr_dabt dabt = info->dabt;
    struct cpu_user_regs *regs = guest_cpu_user_regs();
    register_t *r = select_user_reg(regs, dabt.reg);
    paddr_t offset = info->gpa - d->arch.vuart.info->base_addr;

    perfc_incr(vuart_writes);

    if ( offset == d->arch.vuart.info->data_off )
        /* ignore any status bits */
        vuart_print_char(v, *r & 0xFF);

    return 1;
}
Exemple #11
0
void __domain_crash(struct domain *d)
{
    if ( d == current->domain )
    {
        printk("Domain %d (vcpu#%d) crashed on cpu#%d:\n",
               d->domain_id, current->vcpu_id, smp_processor_id());
        show_registers(guest_cpu_user_regs());
    }
    else
    {
        printk("Domain %d reported crashed by domain %d on cpu#%d:\n",
               d->domain_id, current->domain->domain_id, smp_processor_id());
    }

    domain_shutdown(d, SHUTDOWN_crash);
}
Exemple #12
0
static int vuart_mmio_read(struct vcpu *v, mmio_info_t *info, void *priv)
{
    struct domain *d = v->domain;
    struct hsr_dabt dabt = info->dabt;
    struct cpu_user_regs *regs = guest_cpu_user_regs();
    register_t *r = select_user_reg(regs, dabt.reg);
    paddr_t offset = info->gpa - d->arch.vuart.info->base_addr;

    perfc_incr(vuart_reads);

    /* By default zeroed the register */
    *r = 0;

    if ( offset == d->arch.vuart.info->status_off )
        /* All holding registers empty, ready to send etc */
        *r = d->arch.vuart.info->status;

    return 1;
}
asmlinkage void trace_hypercall(void)
{
    struct cpu_user_regs *regs = guest_cpu_user_regs();

#ifdef __x86_64__
    if ( is_pv_32on64_vcpu(current) )
    {
        struct {
            u32 eip,eax;
        } __attribute__((packed)) d;

        d.eip = regs->eip;
        d.eax = regs->eax;

        __trace_var(TRC_PV_HYPERCALL, 1, sizeof(d), &d);
    }
    else
#endif
    {
Exemple #14
0
void __domain_crash(struct domain *d)
{
    if ( d->is_shutting_down )
    {
        /* Print nothing: the domain is already shutting down. */
    }
    else if ( d == current->domain )
    {
        printk("Domain %d (vcpu#%d) crashed on cpu#%d:\n",
               d->domain_id, current->vcpu_id, smp_processor_id());
        show_execution_state(guest_cpu_user_regs());
    }
    else
    {
        printk("Domain %d reported crashed by domain %d on cpu#%d:\n",
               d->domain_id, current->domain->domain_id, smp_processor_id());
    }

    domain_shutdown(d, SHUTDOWN_crash);
}
Exemple #15
0
void __trace_ptwr_emulation(unsigned long addr, l1_pgentry_t npte)
{
    unsigned long eip = guest_cpu_user_regs()->eip;

    /* We have a couple of different modes to worry about:
     * - 32-on-32: 32-bit pte, 32-bit virtual addresses
     * - pae-on-pae, pae-on-64: 64-bit pte, 32-bit virtual addresses
     * - 64-on-64: 64-bit pte, 64-bit virtual addresses
     * pae-on-64 is the only one that requires extra code; in all other
     * cases, "unsigned long" is the size of a guest virtual address.
     */

    if ( is_pv_32bit_vcpu(current) )
    {
        struct __packed {
            l1_pgentry_t pte;
            u32 addr, eip;
        } d;
        d.addr = addr;
        d.eip = eip;
        d.pte = npte;

        __trace_var(TRC_PV_PTWR_EMULATION_PAE, 1, sizeof(d), &d);
    }
    else
    {
        struct {
            l1_pgentry_t pte;
            unsigned long addr, eip;
        } d;
        unsigned event;

        d.addr = addr;
        d.eip = eip;
        d.pte = npte;

        event = TRC_PV_PTWR_EMULATION;
        event |= TRC_64_FLAG;
        __trace_var(event, 1/*tsc*/, sizeof(d), &d);
    }
}
Exemple #16
0
static int uart0_mmio_read(struct vcpu *v, mmio_info_t *info)
{
    struct hsr_dabt dabt = info->dabt;
    struct cpu_user_regs *regs = guest_cpu_user_regs();
    uint32_t *r = select_user_reg(regs, dabt.reg);
    int offset = (int)(info->gpa - UART0_START);

    switch ( offset )
    {
    case UARTDR:
        *r = 0;
        return 1;
    case UARTFR:
        *r = 0x87; /* All holding registers empty, ready to send etc */
        return 1;
    default:
        printk("VPL011: unhandled read r%d offset %#08x\n",
               dabt.reg, offset);
        domain_crash_synchronous();
    }
}
Exemple #17
0
static int uart0_mmio_write(struct vcpu *v, mmio_info_t *info)
{
    struct hsr_dabt dabt = info->dabt;
    struct cpu_user_regs *regs = guest_cpu_user_regs();
    uint32_t *r = select_user_reg(regs, dabt.reg);
    int offset = (int)(info->gpa - UART0_START);

    switch ( offset )
    {
    case UARTDR:
        /* ignore any status bits */
        uart0_print_char((int)((*r) & 0xFF));
        return 1;
    case UARTFR:
        /* Silently ignore */
        return 1;
    default:
        printk("VPL011: unhandled write r%d=%"PRIx32" offset %#08x\n",
               dabt.reg, *r, offset);
        domain_crash_synchronous();
    }
}
Exemple #18
0
static int fetch(struct vcpu *v, u8 *buf, unsigned long addr, int len)
{
    uint32_t pfec;

    pfec = (vmcb_get_cpl(v->arch.hvm_svm.vmcb) == 3) ? PFEC_user_mode : 0;

    switch ( hvm_fetch_from_guest_virt(buf, addr, len, pfec) )
    {
    case HVMCOPY_okay:
        break;
    case HVMCOPY_bad_gva_to_gfn:
        /* OK just to give up; we'll have injected #PF already */
        return 0;
    default:
        /* Not OK: fetches from non-RAM pages are not supportable. */
        gdprintk(XENLOG_WARNING, "Bad instruction fetch at %#lx (%#lx)\n",
                 (unsigned long) guest_cpu_user_regs()->eip, addr);
        hvm_inject_hw_exception(TRAP_gp_fault, 0);
        return 0;
    }
    return 1;
}
Exemple #19
0
enum mc_disposition arch_do_multicall_call(struct mc_state *state)
{
    struct vcpu *curr = current;
    unsigned long op;

    if ( !is_pv_32bit_vcpu(curr) )
    {
        struct multicall_entry *call = &state->call;

        op = call->op;
        if ( (op < ARRAY_SIZE(pv_hypercall_table)) &&
             pv_hypercall_table[op].native )
            call->result = pv_hypercall_table[op].native(
                call->args[0], call->args[1], call->args[2],
                call->args[3], call->args[4], call->args[5]);
        else
            call->result = -ENOSYS;
    }
#ifdef CONFIG_COMPAT
    else
    {
        struct compat_multicall_entry *call = &state->compat_call;

        op = call->op;
        if ( (op < ARRAY_SIZE(pv_hypercall_table)) &&
             pv_hypercall_table[op].compat )
            call->result = pv_hypercall_table[op].compat(
                call->args[0], call->args[1], call->args[2],
                call->args[3], call->args[4], call->args[5]);
        else
            call->result = -ENOSYS;
    }
#endif

    return unlikely(op == __HYPERVISOR_iret)
           ? mc_exit
           : likely(guest_kernel_mode(curr, guest_cpu_user_regs()))
             ? mc_continue : mc_preempt;
}
Exemple #20
0
static int handle_read(const struct mmio_handler *handler, struct vcpu *v,
                       mmio_info_t *info)
{
    const struct hsr_dabt dabt = info->dabt;
    struct cpu_user_regs *regs = guest_cpu_user_regs();
    /*
     * Initialize to zero to avoid leaking data if there is an
     * implementation error in the emulation (such as not correctly
     * setting r).
     */
    register_t r = 0;
    uint8_t size = (1 << dabt.size) * 8;

    if ( !handler->ops->read(v, info, &r, handler->priv) )
        return 0;

    /*
     * Sign extend if required.
     * Note that we expect the read handler to have zeroed the bits
     * outside the requested access size.
     */
    if ( dabt.sign && (r & (1UL << (size - 1))) )
    {
        /*
         * We are relying on register_t using the same as
         * an unsigned long in order to keep the 32-bit assembly
         * code smaller.
         */
        BUILD_BUG_ON(sizeof(register_t) != sizeof(unsigned long));
        r |= (~0UL) << size;
    }

    set_user_reg(regs, dabt.reg, r);

    return 1;
}
Exemple #21
0
void vmcs_dump_vcpu(struct vcpu *v)
{
    struct cpu_user_regs *regs = &v->arch.guest_context.user_regs;
    unsigned long long x;

    if ( v == current )
        regs = guest_cpu_user_regs();

    vmx_vmcs_enter(v);

    printk("*** Guest State ***\n");
    printk("CR0: actual=0x%016llx, shadow=0x%016llx, gh_mask=%016llx\n",
           (unsigned long long)vmr(GUEST_CR0),
           (unsigned long long)vmr(CR0_READ_SHADOW), 
           (unsigned long long)vmr(CR0_GUEST_HOST_MASK));
    printk("CR4: actual=0x%016llx, shadow=0x%016llx, gh_mask=%016llx\n",
           (unsigned long long)vmr(GUEST_CR4),
           (unsigned long long)vmr(CR4_READ_SHADOW), 
           (unsigned long long)vmr(CR4_GUEST_HOST_MASK));
    printk("CR3: actual=0x%016llx, target_count=%d\n",
           (unsigned long long)vmr(GUEST_CR3),
           (int)vmr(CR3_TARGET_COUNT));
    printk("     target0=%016llx, target1=%016llx\n",
           (unsigned long long)vmr(CR3_TARGET_VALUE0),
           (unsigned long long)vmr(CR3_TARGET_VALUE1));
    printk("     target2=%016llx, target3=%016llx\n",
           (unsigned long long)vmr(CR3_TARGET_VALUE2),
           (unsigned long long)vmr(CR3_TARGET_VALUE3));
    printk("RSP = 0x%016llx (0x%016llx)  RIP = 0x%016llx (0x%016llx)\n", 
           (unsigned long long)vmr(GUEST_RSP),
           (unsigned long long)regs->esp,
           (unsigned long long)vmr(GUEST_RIP),
           (unsigned long long)regs->eip);
    printk("RFLAGS=0x%016llx (0x%016llx)  DR7 = 0x%016llx\n", 
           (unsigned long long)vmr(GUEST_RFLAGS),
           (unsigned long long)regs->eflags,
           (unsigned long long)vmr(GUEST_DR7));
    printk("Sysenter RSP=%016llx CS:RIP=%04x:%016llx\n",
           (unsigned long long)vmr(GUEST_SYSENTER_ESP),
           (int)vmr(GUEST_SYSENTER_CS),
           (unsigned long long)vmr(GUEST_SYSENTER_EIP));
    vmx_dump_sel("CS", x86_seg_cs);
    vmx_dump_sel("DS", x86_seg_ds);
    vmx_dump_sel("SS", x86_seg_ss);
    vmx_dump_sel("ES", x86_seg_es);
    vmx_dump_sel("FS", x86_seg_fs);
    vmx_dump_sel("GS", x86_seg_gs);
    vmx_dump_sel("GDTR", x86_seg_gdtr);
    vmx_dump_sel("LDTR", x86_seg_ldtr);
    vmx_dump_sel("IDTR", x86_seg_idtr);
    vmx_dump_sel("TR", x86_seg_tr);
    x  = (unsigned long long)vmr(TSC_OFFSET_HIGH) << 32;
    x |= (uint32_t)vmr(TSC_OFFSET);
    printk("TSC Offset = %016llx\n", x);
    x  = (unsigned long long)vmr(GUEST_IA32_DEBUGCTL) << 32;
    x |= (uint32_t)vmr(GUEST_IA32_DEBUGCTL);
    printk("DebugCtl=%016llx DebugExceptions=%016llx\n", x,
           (unsigned long long)vmr(GUEST_PENDING_DBG_EXCEPTIONS));
    printk("Interruptibility=%04x ActivityState=%04x\n",
           (int)vmr(GUEST_INTERRUPTIBILITY_INFO),
           (int)vmr(GUEST_ACTIVITY_STATE));

    printk("*** Host State ***\n");
    printk("RSP = 0x%016llx  RIP = 0x%016llx\n", 
           (unsigned long long)vmr(HOST_RSP),
           (unsigned long long)vmr(HOST_RIP));
    printk("CS=%04x DS=%04x ES=%04x FS=%04x GS=%04x SS=%04x TR=%04x\n",
           (uint16_t)vmr(HOST_CS_SELECTOR),
           (uint16_t)vmr(HOST_DS_SELECTOR),
           (uint16_t)vmr(HOST_ES_SELECTOR),
           (uint16_t)vmr(HOST_FS_SELECTOR),
           (uint16_t)vmr(HOST_GS_SELECTOR),
           (uint16_t)vmr(HOST_SS_SELECTOR),
           (uint16_t)vmr(HOST_TR_SELECTOR));
    printk("FSBase=%016llx GSBase=%016llx TRBase=%016llx\n",
           (unsigned long long)vmr(HOST_FS_BASE),
           (unsigned long long)vmr(HOST_GS_BASE),
           (unsigned long long)vmr(HOST_TR_BASE));
    printk("GDTBase=%016llx IDTBase=%016llx\n",
           (unsigned long long)vmr(HOST_GDTR_BASE),
           (unsigned long long)vmr(HOST_IDTR_BASE));
    printk("CR0=%016llx CR3=%016llx CR4=%016llx\n",
           (unsigned long long)vmr(HOST_CR0),
           (unsigned long long)vmr(HOST_CR3),
           (unsigned long long)vmr(HOST_CR4));
    printk("Sysenter RSP=%016llx CS:RIP=%04x:%016llx\n",
           (unsigned long long)vmr(HOST_SYSENTER_ESP),
           (int)vmr(HOST_SYSENTER_CS),
           (unsigned long long)vmr(HOST_SYSENTER_EIP));

    printk("*** Control State ***\n");
    printk("PinBased=%08x CPUBased=%08x SecondaryExec=%08x\n",
           (uint32_t)vmr(PIN_BASED_VM_EXEC_CONTROL),
           (uint32_t)vmr(CPU_BASED_VM_EXEC_CONTROL),
           (uint32_t)vmr(SECONDARY_VM_EXEC_CONTROL));
    printk("EntryControls=%08x ExitControls=%08x\n",
           (uint32_t)vmr(VM_ENTRY_CONTROLS),
           (uint32_t)vmr(VM_EXIT_CONTROLS));
    printk("ExceptionBitmap=%08x\n",
           (uint32_t)vmr(EXCEPTION_BITMAP));
    printk("VMEntry: intr_info=%08x errcode=%08x ilen=%08x\n",
           (uint32_t)vmr(VM_ENTRY_INTR_INFO),
           (uint32_t)vmr(VM_ENTRY_EXCEPTION_ERROR_CODE),
           (uint32_t)vmr(VM_ENTRY_INSTRUCTION_LEN));
    printk("VMExit: intr_info=%08x errcode=%08x ilen=%08x\n",
           (uint32_t)vmr(VM_EXIT_INTR_INFO),
           (uint32_t)vmr(VM_EXIT_INTR_ERROR_CODE),
           (uint32_t)vmr(VM_ENTRY_INSTRUCTION_LEN));
    printk("        reason=%08x qualification=%08x\n",
           (uint32_t)vmr(VM_EXIT_REASON),
           (uint32_t)vmr(EXIT_QUALIFICATION));
    printk("IDTVectoring: info=%08x errcode=%08x\n",
           (uint32_t)vmr(IDT_VECTORING_INFO),
           (uint32_t)vmr(IDT_VECTORING_ERROR_CODE));
    printk("TPR Threshold = 0x%02x\n",
           (uint32_t)vmr(TPR_THRESHOLD));

    vmx_vmcs_exit(v);
}
Exemple #22
0
Fichier : vpmu.c Projet : Fantu/Xen
void vpmu_do_interrupt(struct cpu_user_regs *regs)
{
    struct vcpu *sampled = current, *sampling;
    struct vpmu_struct *vpmu;
    struct vlapic *vlapic;
    u32 vlapic_lvtpc;

    /*
     * dom0 will handle interrupt for special domains (e.g. idle domain) or,
     * in XENPMU_MODE_ALL, for everyone.
     */
    if ( (vpmu_mode & XENPMU_MODE_ALL) ||
         (sampled->domain->domain_id >= DOMID_FIRST_RESERVED) )
    {
        sampling = choose_hwdom_vcpu();
        if ( !sampling )
            return;
    }
    else
        sampling = sampled;

    vpmu = vcpu_vpmu(sampling);
    if ( !vpmu->arch_vpmu_ops )
        return;

    /* PV(H) guest */
    if ( !is_hvm_vcpu(sampling) || (vpmu_mode & XENPMU_MODE_ALL) )
    {
        const struct cpu_user_regs *cur_regs;
        uint64_t *flags = &vpmu->xenpmu_data->pmu.pmu_flags;
        domid_t domid;

        if ( !vpmu->xenpmu_data )
            return;

        if ( is_pvh_vcpu(sampling) &&
             !(vpmu_mode & XENPMU_MODE_ALL) &&
             !vpmu->arch_vpmu_ops->do_interrupt(regs) )
            return;

        if ( vpmu_is_set(vpmu, VPMU_CACHED) )
            return;

        /* PV guest will be reading PMU MSRs from xenpmu_data */
        vpmu_set(vpmu, VPMU_CONTEXT_SAVE | VPMU_CONTEXT_LOADED);
        vpmu->arch_vpmu_ops->arch_vpmu_save(sampling, 1);
        vpmu_reset(vpmu, VPMU_CONTEXT_SAVE | VPMU_CONTEXT_LOADED);

        if ( has_hvm_container_vcpu(sampled) )
            *flags = 0;
        else
            *flags = PMU_SAMPLE_PV;

        if ( sampled == sampling )
            domid = DOMID_SELF;
        else
            domid = sampled->domain->domain_id;

        /* Store appropriate registers in xenpmu_data */
        /* FIXME: 32-bit PVH should go here as well */
        if ( is_pv_32bit_vcpu(sampling) )
        {
            /*
             * 32-bit dom0 cannot process Xen's addresses (which are 64 bit)
             * and therefore we treat it the same way as a non-privileged
             * PV 32-bit domain.
             */
            struct compat_pmu_regs *cmp;

            cur_regs = guest_cpu_user_regs();

            cmp = (void *)&vpmu->xenpmu_data->pmu.r.regs;
            cmp->ip = cur_regs->rip;
            cmp->sp = cur_regs->rsp;
            cmp->flags = cur_regs->eflags;
            cmp->ss = cur_regs->ss;
            cmp->cs = cur_regs->cs;
            if ( (cmp->cs & 3) > 1 )
                *flags |= PMU_SAMPLE_USER;
        }
        else
        {
            struct xen_pmu_regs *r = &vpmu->xenpmu_data->pmu.r.regs;

            if ( (vpmu_mode & XENPMU_MODE_SELF) )
                cur_regs = guest_cpu_user_regs();
            else if ( !guest_mode(regs) &&
                      is_hardware_domain(sampling->domain) )
            {
                cur_regs = regs;
                domid = DOMID_XEN;
            }
            else
                cur_regs = guest_cpu_user_regs();

            r->ip = cur_regs->rip;
            r->sp = cur_regs->rsp;
            r->flags = cur_regs->eflags;

            if ( !has_hvm_container_vcpu(sampled) )
            {
                r->ss = cur_regs->ss;
                r->cs = cur_regs->cs;
                if ( !(sampled->arch.flags & TF_kernel_mode) )
                    *flags |= PMU_SAMPLE_USER;
            }
            else
            {
                struct segment_register seg;

                hvm_get_segment_register(sampled, x86_seg_cs, &seg);
                r->cs = seg.sel;
                hvm_get_segment_register(sampled, x86_seg_ss, &seg);
                r->ss = seg.sel;
                r->cpl = seg.attr.fields.dpl;
                if ( !(sampled->arch.hvm_vcpu.guest_cr[0] & X86_CR0_PE) )
                    *flags |= PMU_SAMPLE_REAL;
            }
        }

        vpmu->xenpmu_data->domain_id = domid;
        vpmu->xenpmu_data->vcpu_id = sampled->vcpu_id;
        if ( is_hardware_domain(sampling->domain) )
            vpmu->xenpmu_data->pcpu_id = smp_processor_id();
        else
            vpmu->xenpmu_data->pcpu_id = sampled->vcpu_id;

        vpmu->hw_lapic_lvtpc |= APIC_LVT_MASKED;
        apic_write(APIC_LVTPC, vpmu->hw_lapic_lvtpc);
        *flags |= PMU_CACHED;
        vpmu_set(vpmu, VPMU_CACHED);

        send_guest_vcpu_virq(sampling, VIRQ_XENPMU);

        return;
    }

    /* HVM guests */
    vlapic = vcpu_vlapic(sampling);

    /* We don't support (yet) HVM dom0 */
    ASSERT(sampling == sampled);

    if ( !vpmu->arch_vpmu_ops->do_interrupt(regs) ||
         !is_vlapic_lvtpc_enabled(vlapic) )
        return;

    vlapic_lvtpc = vlapic_get_reg(vlapic, APIC_LVTPC);

    switch ( GET_APIC_DELIVERY_MODE(vlapic_lvtpc) )
    {
    case APIC_MODE_FIXED:
        vlapic_set_irq(vlapic, vlapic_lvtpc & APIC_VECTOR_MASK, 0);
        break;
    case APIC_MODE_NMI:
        sampling->nmi_pending = 1;
        break;
    }
}
Exemple #23
0
unsigned int compat_iret(void)
{
    struct cpu_user_regs *regs = guest_cpu_user_regs();
    struct vcpu *v = current;
    u32 eflags;

    /* Trim stack pointer to 32 bits. */
    regs->rsp = (u32)regs->rsp;

    /* Restore EAX (clobbered by hypercall). */
    if ( unlikely(__get_user(regs->eax, (u32 *)regs->rsp)) )
    {
        domain_crash(v->domain);
        return 0;
    }

    /* Restore CS and EIP. */
    if ( unlikely(__get_user(regs->eip, (u32 *)regs->rsp + 1)) ||
        unlikely(__get_user(regs->cs, (u32 *)regs->rsp + 2)) )
    {
        domain_crash(v->domain);
        return 0;
    }

    /*
     * Fix up and restore EFLAGS. We fix up in a local staging area
     * to avoid firing the BUG_ON(IOPL) check in arch_get_info_guest.
     */
    if ( unlikely(__get_user(eflags, (u32 *)regs->rsp + 3)) )
    {
        domain_crash(v->domain);
        return 0;
    }

    if ( VM_ASSIST(v->domain, architectural_iopl) )
        v->arch.pv_vcpu.iopl = eflags & X86_EFLAGS_IOPL;

    regs->eflags = (eflags & ~X86_EFLAGS_IOPL) | X86_EFLAGS_IF;

    if ( unlikely(eflags & X86_EFLAGS_VM) )
    {
        /*
         * Cannot return to VM86 mode: inject a GP fault instead. Note that
         * the GP fault is reported on the first VM86 mode instruction, not on
         * the IRET (which is why we can simply leave the stack frame as-is
         * (except for perhaps having to copy it), which in turn seems better
         * than teaching create_bounce_frame() to needlessly deal with vm86
         * mode frames).
         */
        const struct trap_info *ti;
        u32 x, ksp = v->arch.pv_vcpu.kernel_sp - 40;
        unsigned int i;
        int rc = 0;

        gdprintk(XENLOG_ERR, "VM86 mode unavailable (ksp:%08X->%08X)\n",
                 regs->esp, ksp);
        if ( ksp < regs->esp )
        {
            for (i = 1; i < 10; ++i)
            {
                rc |= __get_user(x, (u32 *)regs->rsp + i);
                rc |= __put_user(x, (u32 *)(unsigned long)ksp + i);
            }
        }
        else if ( ksp > regs->esp )
        {
            for ( i = 9; i > 0; --i )
            {
                rc |= __get_user(x, (u32 *)regs->rsp + i);
                rc |= __put_user(x, (u32 *)(unsigned long)ksp + i);
            }
        }
        if ( rc )
        {
            domain_crash(v->domain);
            return 0;
        }
        regs->esp = ksp;
        regs->ss = v->arch.pv_vcpu.kernel_ss;

        ti = &v->arch.pv_vcpu.trap_ctxt[TRAP_gp_fault];
        if ( TI_GET_IF(ti) )
            eflags &= ~X86_EFLAGS_IF;
        regs->eflags &= ~(X86_EFLAGS_VM|X86_EFLAGS_RF|
                          X86_EFLAGS_NT|X86_EFLAGS_TF);
        if ( unlikely(__put_user(0, (u32 *)regs->rsp)) )
        {
            domain_crash(v->domain);
            return 0;
        }
        regs->eip = ti->address;
        regs->cs = ti->cs;
    }
    else if ( unlikely(ring_0(regs)) )
    {
        domain_crash(v->domain);
        return 0;
    }
    else if ( ring_1(regs) )
        regs->esp += 16;
    /* Return to ring 2/3: restore ESP and SS. */
    else if ( __get_user(regs->ss, (u32 *)regs->rsp + 5) ||
              __get_user(regs->esp, (u32 *)regs->rsp + 4) )
    {
        domain_crash(v->domain);
        return 0;
    }

    /* Restore upcall mask from supplied EFLAGS.IF. */
    vcpu_info(v, evtchn_upcall_mask) = !(eflags & X86_EFLAGS_IF);

    async_exception_cleanup(v);

    /*
     * The hypercall exit path will overwrite EAX with this return
     * value.
     */
    return regs->eax;
}