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); }
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); } }
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); }
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; }
unsigned long hypercall_create_continuation( unsigned int op, const char *format, ...) { struct mc_state *mcs = ¤t->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; }
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 }
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); }
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; }
void hypercall_cancel_continuation(void) { struct cpu_user_regs *regs = guest_cpu_user_regs(); struct mc_state *mcs = ¤t->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' */ } }
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; }
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); }
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 {
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); }
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); } }
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(); } }
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(); } }
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; }
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; }
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; }
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); }
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; } }
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; }