/* Used to indicate that a guest page fault needs to be handled */ #define RESUME_PAGE_FAULT (RESUME_GUEST | RESUME_FLAG_ARCH1) /* Used to indicate that a guest passthrough interrupt needs to be handled */ #define RESUME_PASSTHROUGH (RESUME_GUEST | RESUME_FLAG_ARCH2)
/* Used as a "null" value for timebase values */ #define TB_NIL (~(u64)0)
staticint dynamic_mt_modes = 6;
module_param(dynamic_mt_modes, int, 0644);
MODULE_PARM_DESC(dynamic_mt_modes, "Set of allowed dynamic micro-threading modes: 0 (= none), 2, 4, or 6 (= 2 or 4)"); staticint target_smt_mode;
module_param(target_smt_mode, int, 0644);
MODULE_PARM_DESC(target_smt_mode, "Target threads per core (0 = max)");
staticbool one_vm_per_core;
module_param(one_vm_per_core, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(one_vm_per_core, "Only run vCPUs from the same VM on a core (requires POWER8 or older)");
module_param_cb(h_ipi_redirect, &module_param_ops, &h_ipi_redirect, 0644);
MODULE_PARM_DESC(h_ipi_redirect, "Redirect H_IPI wakeup to a free host core"); #endif
/* If set, guests are allowed to create and control nested guests */ staticbool nested = true;
module_param(nested, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(nested, "Enable nested virtualization (only on POWER9)");
/* Used to traverse the list of runnable threads for a given vcore */ #define for_each_runnable_thread(i, vcpu, vc) \ for (i = -1; (vcpu = next_runnable_thread(vc, &i)); )
/* If we're a nested hypervisor, fall back to ordinary IPIs for now */ if (kvmhv_on_pseries()) returnfalse;
/* On POWER9 we can use msgsnd to IPI any cpu */ if (cpu_has_feature(CPU_FTR_ARCH_300)) {
msg |= get_hard_smp_processor_id(cpu);
smp_mb();
__asm__ __volatile__ (PPC_MSGSND(%0) : : "r" (msg)); returntrue;
}
/* On POWER8 for IPIs to threads in the same core, use msgsnd */ if (cpu_has_feature(CPU_FTR_ARCH_207S)) {
preempt_disable(); if (cpu_first_thread_sibling(cpu) ==
cpu_first_thread_sibling(smp_processor_id())) {
msg |= cpu_thread_in_core(cpu);
smp_mb();
__asm__ __volatile__ (PPC_MSGSND(%0) : : "r" (msg));
preempt_enable(); returntrue;
}
preempt_enable();
}
#ifdefined(CONFIG_PPC_ICP_NATIVE) && defined(CONFIG_SMP) if (cpu >= 0 && cpu < nr_cpu_ids) { if (paca_ptrs[cpu]->kvm_hstate.xics_phys) {
xics_wake_cpu(cpu); returntrue;
}
opal_int_set_mfrr(get_hard_smp_processor_id(cpu), IPI_PRIORITY); returntrue;
} #endif
returnfalse;
}
staticvoid kvmppc_fast_vcpu_kick_hv(struct kvm_vcpu *vcpu)
{ int cpu; struct rcuwait *waitp;
/* Dummy value used in computing PCR value below */ #define PCR_ARCH_31 (PCR_ARCH_300 << 1)
staticinlineunsignedlong map_pcr_to_cap(unsignedlong pcr)
{ unsignedlong cap = 0;
switch (pcr) { case PCR_ARCH_300:
cap = H_GUEST_CAP_POWER9; break; case PCR_ARCH_31: if (cpu_has_feature(CPU_FTR_P11_PVR))
cap = H_GUEST_CAP_POWER11; else
cap = H_GUEST_CAP_POWER10; break; default: break;
}
/* We can (emulate) our own architecture version and anything older */ if (cpu_has_feature(CPU_FTR_P11_PVR) || cpu_has_feature(CPU_FTR_ARCH_31))
host_pcr_bit = PCR_ARCH_31; elseif (cpu_has_feature(CPU_FTR_ARCH_300))
host_pcr_bit = PCR_ARCH_300; elseif (cpu_has_feature(CPU_FTR_ARCH_207S))
host_pcr_bit = PCR_ARCH_207; elseif (cpu_has_feature(CPU_FTR_ARCH_206))
host_pcr_bit = PCR_ARCH_206; else
host_pcr_bit = PCR_ARCH_205;
/* Determine lowest PCR bit needed to run guest in given PVR level */
guest_pcr_bit = host_pcr_bit; if (arch_compat) { switch (arch_compat) { case PVR_ARCH_205:
guest_pcr_bit = PCR_ARCH_205; break; case PVR_ARCH_206: case PVR_ARCH_206p:
guest_pcr_bit = PCR_ARCH_206; break; case PVR_ARCH_207:
guest_pcr_bit = PCR_ARCH_207; break; case PVR_ARCH_300:
guest_pcr_bit = PCR_ARCH_300; break; case PVR_ARCH_31: case PVR_ARCH_31_P11:
guest_pcr_bit = PCR_ARCH_31; break; default: return -EINVAL;
}
}
/* Length for a per-processor buffer is passed in at offset 4 in the buffer */ struct reg_vpa {
u32 dummy; union {
__be16 hword;
__be32 word;
} length;
};
case H_VPA_REG_DTL: /* register DTL */ if (len < sizeof(struct dtl_entry)) break;
len -= len % sizeof(struct dtl_entry);
/* Check that they have previously registered a VPA */
err = H_RESOURCE; if (!vpa_is_registered(&tvcpu->arch.vpa)) break;
vpap = &tvcpu->arch.dtl;
err = 0; break;
case H_VPA_REG_SLB: /* register SLB shadow buffer */ /* Check that they have previously registered a VPA */
err = H_RESOURCE; if (!vpa_is_registered(&tvcpu->arch.vpa)) break;
vpap = &tvcpu->arch.slb_shadow;
err = 0; break;
case H_VPA_DEREG_VPA: /* deregister VPA */ /* Check they don't still have a DTL or SLB buf registered */
err = H_RESOURCE; if (vpa_is_registered(&tvcpu->arch.dtl) ||
vpa_is_registered(&tvcpu->arch.slb_shadow)) break;
/* *Weneedtopinthepagepointedtobyvpap->next_gpa, *butwecan'tcallkvmppc_pin_guest_pageunderthelock *asitdoesget_user_pages()anddown_read().Sowe *havetodropthelock,pinthepage,thengetthelock *againandcheckthatanewareadidn'tgetregistered *inthemeantime.
*/ for (;;) {
gpa = vpap->next_gpa;
spin_unlock(&vcpu->arch.vpa_update_lock);
va = NULL;
nb = 0; if (gpa)
va = kvmppc_pin_guest_page(kvm, gpa, &nb);
spin_lock(&vcpu->arch.vpa_update_lock); if (gpa == vpap->next_gpa) break; /* sigh... unpin that one and try again */ if (va)
kvmppc_unpin_guest_page(kvm, va, gpa, false);
}
vpap->update_pending = 0; if (va && nb < vpap->len) { /* *Ifit'snowtooshort,itmustbethatuserspace *haschangedthemappingsunderlyingguestmemory, *sounregistertheregion.
*/
kvmppc_unpin_guest_page(kvm, va, gpa, false);
va = NULL;
}
*old_vpap = *vpap;
vpap->gpa = gpa;
vpap->pinned_addr = va;
vpap->dirty = false; if (va)
vpap->pinned_end = va + vpap->len;
}
/* See if there is a doorbell interrupt pending for a vcpu */ staticbool kvmppc_doorbell_pending(struct kvm_vcpu *vcpu)
{ int thr; struct kvmppc_vcore *vc;
staticbool kvmppc_power8_compatible(struct kvm_vcpu *vcpu)
{ if (kvmppc_get_arch_compat(vcpu) >= PVR_ARCH_207) returntrue; if ((!kvmppc_get_arch_compat(vcpu)) &&
cpu_has_feature(CPU_FTR_ARCH_207S)) returntrue; returnfalse;
}
staticint kvmppc_h_set_mode(struct kvm_vcpu *vcpu, unsignedlong mflags, unsignedlong resource, unsignedlong value1, unsignedlong value2)
{ switch (resource) { case H_SET_MODE_RESOURCE_SET_CIABR: if (!kvmppc_power8_compatible(vcpu)) return H_P2; if (value2) return H_P4; if (mflags) return H_UNSUPPORTED_FLAG_START; /* Guests can't breakpoint the hypervisor */ if ((value1 & CIABR_PRIV) == CIABR_PRIV_HYPER) return H_P3;
kvmppc_set_ciabr_hv(vcpu, value1); return H_SUCCESS; case H_SET_MODE_RESOURCE_SET_DAWR0: if (!kvmppc_power8_compatible(vcpu)) return H_P2; if (!ppc_breakpoint_available()) return H_P2; if (mflags) return H_UNSUPPORTED_FLAG_START; if (value2 & DABRX_HYP) return H_P4;
kvmppc_set_dawr0_hv(vcpu, value1);
kvmppc_set_dawrx0_hv(vcpu, value2); return H_SUCCESS; case H_SET_MODE_RESOURCE_SET_DAWR1: if (!kvmppc_power8_compatible(vcpu)) return H_P2; if (!ppc_breakpoint_available()) return H_P2; if (!cpu_has_feature(CPU_FTR_DAWR1)) return H_P2; if (!vcpu->kvm->arch.dawr1_enabled) return H_FUNCTION; if (mflags) return H_UNSUPPORTED_FLAG_START; if (value2 & DABRX_HYP) return H_P4;
kvmppc_set_dawr1_hv(vcpu, value1);
kvmppc_set_dawrx1_hv(vcpu, value2); return H_SUCCESS; case H_SET_MODE_RESOURCE_ADDR_TRANS_MODE: /* *KVMdoesnotsupportmflags=2(AIL=2)andAIL=1isreserved. *Keepthisinsynchwithkvmppc_filter_guest_lpcr_hv.
*/ if (cpu_has_feature(CPU_FTR_P9_RADIX_PREFETCH_BUG) &&
kvmhv_vcpu_is_radix(vcpu) && mflags == 3) return H_UNSUPPORTED_FLAG_START; return H_TOO_HARD; default: return H_TOO_HARD;
}
}
/* Copy guest memory in place - must reside within a single memslot */ staticint kvmppc_copy_guest(struct kvm *kvm, gpa_t to, gpa_t from, unsignedlong len)
{ struct kvm_memory_slot *to_memslot = NULL; struct kvm_memory_slot *from_memslot = NULL; unsignedlong to_addr, from_addr; int r;
/* Get HPA for from address */
from_memslot = gfn_to_memslot(kvm, from >> PAGE_SHIFT); if (!from_memslot) return -EFAULT; if ((from + len) >= ((from_memslot->base_gfn + from_memslot->npages)
<< PAGE_SHIFT)) return -EINVAL;
from_addr = gfn_to_hva_memslot(from_memslot, from >> PAGE_SHIFT); if (kvm_is_error_hva(from_addr)) return -EFAULT;
from_addr |= (from & (PAGE_SIZE - 1));
/* Get HPA for to address */
to_memslot = gfn_to_memslot(kvm, to >> PAGE_SHIFT); if (!to_memslot) return -EFAULT; if ((to + len) >= ((to_memslot->base_gfn + to_memslot->npages)
<< PAGE_SHIFT)) return -EINVAL;
to_addr = gfn_to_hva_memslot(to_memslot, to >> PAGE_SHIFT); if (kvm_is_error_hva(to_addr)) return -EFAULT;
to_addr |= (to & (PAGE_SIZE - 1));
/* Perform copy */
r = raw_copy_in_user((void __user *)to_addr, (void __user *)from_addr,
len); if (r) return -EFAULT;
mark_page_dirty(kvm, to >> PAGE_SHIFT); return0;
}
/* Check for invalid flags (H_PAGE_SET_LOANED covers all CMO flags) */ if (flags & ~(H_ICACHE_INVALIDATE | H_ICACHE_SYNCHRONIZE |
H_ZERO_PAGE | H_COPY_PAGE | H_PAGE_SET_LOANED)) return H_PARAMETER;
/* dest (and src if copy_page flag set) must be page aligned */ if ((dest & pg_mask) || ((flags & H_COPY_PAGE) && (src & pg_mask))) return H_PARAMETER;
/* zero and/or copy the page as determined by the flags */ if (flags & H_COPY_PAGE) {
ret = kvmppc_copy_guest(vcpu->kvm, dest, src, pg_sz); if (ret < 0) return H_PARAMETER;
} elseif (flags & H_ZERO_PAGE) {
ret = kvm_clear_guest(vcpu->kvm, dest, pg_sz); if (ret < 0) return H_PARAMETER;
}
/* Send the error out to userspace via KVM_RUN */ return rc; case H_LOGICAL_CI_LOAD:
ret = kvmppc_h_logical_ci_load(vcpu); if (ret == H_TOO_HARD) return RESUME_HOST; break; case H_LOGICAL_CI_STORE:
ret = kvmppc_h_logical_ci_store(vcpu); if (ret == H_TOO_HARD) return RESUME_HOST; break; case H_SET_MODE:
ret = kvmppc_h_set_mode(vcpu, kvmppc_get_gpr(vcpu, 4),
kvmppc_get_gpr(vcpu, 5),
kvmppc_get_gpr(vcpu, 6),
kvmppc_get_gpr(vcpu, 7)); if (ret == H_TOO_HARD) return RESUME_HOST; break; case H_XIRR: case H_CPPR: case H_EOI: case H_IPI: case H_IPOLL: case H_XIRR_X: if (kvmppc_xics_enabled(vcpu)) { if (xics_on_xive()) {
ret = H_NOT_AVAILABLE; return RESUME_GUEST;
}
ret = kvmppc_xics_hcall(vcpu, req); break;
} return RESUME_HOST; case H_SET_DABR:
ret = kvmppc_h_set_dabr(vcpu, kvmppc_get_gpr(vcpu, 4)); break; case H_SET_XDABR:
ret = kvmppc_h_set_xdabr(vcpu, kvmppc_get_gpr(vcpu, 4),
kvmppc_get_gpr(vcpu, 5)); break; #ifdef CONFIG_SPAPR_TCE_IOMMU case H_GET_TCE:
ret = kvmppc_h_get_tce(vcpu, kvmppc_get_gpr(vcpu, 4),
kvmppc_get_gpr(vcpu, 5)); if (ret == H_TOO_HARD) return RESUME_HOST; break; case H_PUT_TCE:
ret = kvmppc_h_put_tce(vcpu, kvmppc_get_gpr(vcpu, 4),
kvmppc_get_gpr(vcpu, 5),
kvmppc_get_gpr(vcpu, 6)); if (ret == H_TOO_HARD) return RESUME_HOST; break; case H_PUT_TCE_INDIRECT:
ret = kvmppc_h_put_tce_indirect(vcpu, kvmppc_get_gpr(vcpu, 4),
kvmppc_get_gpr(vcpu, 5),
kvmppc_get_gpr(vcpu, 6),
kvmppc_get_gpr(vcpu, 7)); if (ret == H_TOO_HARD) return RESUME_HOST; break; case H_STUFF_TCE:
ret = kvmppc_h_stuff_tce(vcpu, kvmppc_get_gpr(vcpu, 4),
kvmppc_get_gpr(vcpu, 5),
kvmppc_get_gpr(vcpu, 6),
kvmppc_get_gpr(vcpu, 7)); if (ret == H_TOO_HARD) return RESUME_HOST; break; #endif case H_RANDOM: { unsignedlong rand;
if (!arch_get_random_seed_longs(&rand, 1))
ret = H_HARDWARE;
kvmppc_set_gpr(vcpu, 4, rand); break;
} case H_RPT_INVALIDATE:
ret = kvmppc_h_rpt_invalidate(vcpu, kvmppc_get_gpr(vcpu, 4),
kvmppc_get_gpr(vcpu, 5),
kvmppc_get_gpr(vcpu, 6),
kvmppc_get_gpr(vcpu, 7),
kvmppc_get_gpr(vcpu, 8),
kvmppc_get_gpr(vcpu, 9)); break;
case H_SET_PARTITION_TABLE:
ret = H_FUNCTION; if (nesting_enabled(kvm))
ret = kvmhv_set_partition_table(vcpu); break; case H_ENTER_NESTED:
ret = H_FUNCTION; if (!nesting_enabled(kvm)) break;
ret = kvmhv_enter_nested_guest(vcpu); if (ret == H_INTERRUPT) {
kvmppc_set_gpr(vcpu, 3, 0);
vcpu->arch.hcall_needed = 0; return -EINTR;
} elseif (ret == H_TOO_HARD) {
kvmppc_set_gpr(vcpu, 3, 0);
vcpu->arch.hcall_needed = 0; return RESUME_HOST;
} break; case H_TLB_INVALIDATE:
ret = H_FUNCTION; if (nesting_enabled(kvm))
ret = kvmhv_do_nested_tlbie(vcpu); break; case H_COPY_TOFROM_GUEST:
ret = H_FUNCTION; if (nesting_enabled(kvm))
ret = kvmhv_copy_tofrom_guest_nested(vcpu); break; case H_PAGE_INIT:
ret = kvmppc_h_page_init(vcpu, kvmppc_get_gpr(vcpu, 4),
kvmppc_get_gpr(vcpu, 5),
kvmppc_get_gpr(vcpu, 6)); break; case H_SVM_PAGE_IN:
ret = H_UNSUPPORTED; if (kvmppc_get_srr1(vcpu) & MSR_S)
ret = kvmppc_h_svm_page_in(kvm,
kvmppc_get_gpr(vcpu, 4),
kvmppc_get_gpr(vcpu, 5),
kvmppc_get_gpr(vcpu, 6)); break; case H_SVM_PAGE_OUT:
ret = H_UNSUPPORTED; if (kvmppc_get_srr1(vcpu) & MSR_S)
ret = kvmppc_h_svm_page_out(kvm,
kvmppc_get_gpr(vcpu, 4),
kvmppc_get_gpr(vcpu, 5),
kvmppc_get_gpr(vcpu, 6)); break; case H_SVM_INIT_START:
ret = H_UNSUPPORTED; if (kvmppc_get_srr1(vcpu) & MSR_S)
ret = kvmppc_h_svm_init_start(kvm); break; case H_SVM_INIT_DONE:
ret = H_UNSUPPORTED; if (kvmppc_get_srr1(vcpu) & MSR_S)
ret = kvmppc_h_svm_init_done(kvm); break; case H_SVM_INIT_ABORT: /* *EvenifthatcallismadebytheUltravisor,theSSR1value *istheguestcontextone,withthesecurebitclearasithas *notyetbeensecured.Sowecan'tcheckithere. *Insteadthekvm->arch.secure_guestflagischeckedinside *kvmppc_h_svm_init_abort().
*/
ret = kvmppc_h_svm_init_abort(kvm); break;
staticint kvmppc_hcall_impl_hv(unsignedlong cmd)
{ switch (cmd) { case H_CEDE: case H_PROD: case H_CONFER: case H_REGISTER_VPA: case H_SET_MODE: #ifdef CONFIG_SPAPR_TCE_IOMMU case H_GET_TCE: case H_PUT_TCE: case H_PUT_TCE_INDIRECT: case H_STUFF_TCE: #endif case H_LOGICAL_CI_LOAD: case H_LOGICAL_CI_STORE: #ifdef CONFIG_KVM_XICS case H_XIRR: case H_CPPR: case H_EOI: case H_IPI: case H_IPOLL: case H_XIRR_X: #endif case H_PAGE_INIT: case H_RPT_INVALIDATE: return1;
}
/* See if it's in the real-mode table */ return kvmppc_hcall_impl_hv_realmode(cmd);
}
staticint kvmppc_handle_exit_hv(struct kvm_vcpu *vcpu, struct task_struct *tsk)
{ struct kvm_run *run = vcpu->run; int r = RESUME_HOST;
vcpu->stat.sum_exits++;
/* *Thiscanhappenifaninterruptoccursinthelaststages *ofguestentryorthefirststagesofguestexit(i.e.after *settingpaca->kvm_hstate.in_guesttoKVM_GUEST_MODE_GUEST_HV *andbeforesettingittoKVM_GUEST_MODE_HOST_HV). *Thatcanhappenduetoabug,orduetoamachinecheck *occurringatjustthewrongtime.
*/ if (!kvmhv_is_nestedv2() && (__kvmppc_get_msr_hv(vcpu) & MSR_HV)) {
printk(KERN_EMERG "KVM trap in HV mode!\n");
printk(KERN_EMERG "trap=0x%x | pc=0x%lx | msr=0x%llx\n",
vcpu->arch.trap, kvmppc_get_pc(vcpu),
vcpu->arch.shregs.msr);
kvmppc_dump_regs(vcpu);
run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
run->hw.hardware_exit_reason = vcpu->arch.trap; return RESUME_HOST;
}
run->exit_reason = KVM_EXIT_UNKNOWN;
run->ready_for_interrupt_injection = 1; switch (vcpu->arch.trap) { /* We're good on these - the host merely wanted to get our attention */ case BOOK3S_INTERRUPT_NESTED_HV_DECREMENTER:
WARN_ON_ONCE(1); /* Should never happen */
vcpu->arch.trap = BOOK3S_INTERRUPT_HV_DECREMENTER;
fallthrough; case BOOK3S_INTERRUPT_HV_DECREMENTER:
vcpu->stat.dec_exits++;
r = RESUME_GUEST; break; case BOOK3S_INTERRUPT_EXTERNAL: case BOOK3S_INTERRUPT_H_DOORBELL: case BOOK3S_INTERRUPT_H_VIRT:
vcpu->stat.ext_intr_exits++;
r = RESUME_GUEST; break; /* SR/HMI/PMI are HV interrupts that host has handled. Resume guest.*/ case BOOK3S_INTERRUPT_HMI: case BOOK3S_INTERRUPT_PERFMON: case BOOK3S_INTERRUPT_SYSTEM_RESET:
r = RESUME_GUEST; break; case BOOK3S_INTERRUPT_MACHINE_CHECK: { static DEFINE_RATELIMIT_STATE(rs, DEFAULT_RATELIMIT_INTERVAL,
DEFAULT_RATELIMIT_BURST); /* *PrinttheMCEeventtohostconsole.Ratelimitsotheguest *can'tfloodthehostlog.
*/ if (__ratelimit(&rs))
machine_check_print_event_info(&vcpu->arch.mce_evt,false, true);
/* Exit to guest with KVM_EXIT_NMI as exit reason */
run->exit_reason = KVM_EXIT_NMI;
run->hw.hardware_exit_reason = vcpu->arch.trap; /* Clear out the old NMI status from run->flags */
run->flags &= ~KVM_RUN_PPC_NMI_DISP_MASK; /* Now set the NMI status */ if (vcpu->arch.mce_evt.disposition == MCE_DISPOSITION_RECOVERED)
run->flags |= KVM_RUN_PPC_NMI_DISP_FULLY_RECOV; else
run->flags |= KVM_RUN_PPC_NMI_DISP_NOT_RECOV;
r = RESUME_HOST; break;
} case BOOK3S_INTERRUPT_PROGRAM:
{
ulong flags; /* *Normallyprograminterruptsaredelivereddirectly *totheguestbythehardware,butwecangethere *asaresultofahypervisoremulationinterrupt *(e40)gettingturnedintoa700byBMLRTAS.
*/
flags = (__kvmppc_get_msr_hv(vcpu) & 0x1f0000ull) |
(kvmppc_get_msr(vcpu) & SRR1_PREFIXED);
kvmppc_core_queue_program(vcpu, flags);
r = RESUME_GUEST; break;
} case BOOK3S_INTERRUPT_SYSCALL:
{ int i;
/* *hcall-gatherargsandsetexit_reason.Thiswillnextbe *handledbykvmppc_pseries_do_hcallwhichmaybeabletodeal *withitandresumeguest,ormaypunttouserspace.
*/
run->papr_hcall.nr = kvmppc_get_gpr(vcpu, 3); for (i = 0; i < 9; ++i)
run->papr_hcall.args[i] = kvmppc_get_gpr(vcpu, 4 + i);
run->exit_reason = KVM_EXIT_PAPR_HCALL;
vcpu->arch.hcall_needed = 1;
r = RESUME_HOST; break;
} /* *Wegetthesenexttwoiftheguestaccessesapagewhichitthinks *ithasmappedbutwhichisnotactuallypresent,eitherbecause *itisforanemulatedI/Odeviceorbecausethecorresonding *hostpagehasbeenpagedout. * *AnyotherHDSI/HISIinterruptshavebeenhandledalreadyforP7/8 *guests.ForPOWER9hashguestsnotusingrmhandlers,basichash *faulthandlingisdonehere.
*/ case BOOK3S_INTERRUPT_H_DATA_STORAGE: { unsignedlong vsid; long err;
if (cpu_has_feature(CPU_FTR_P9_RADIX_PREFETCH_BUG) &&
unlikely(vcpu->arch.fault_dsisr == HDSISR_CANARY)) {
r = RESUME_GUEST; /* Just retry if it's the canary */ break;
}
if (kvm_is_radix(vcpu->kvm) || !cpu_has_feature(CPU_FTR_ARCH_300)) { /* *Radixdoesn'trequireanything,andpre-ISAv3.0hash *alreadyattemptedtohandlethisinrmhandlers.The *hashfaulthandlingbelowisv3only(itusesASDR *viafault_gpa).
*/
r = RESUME_PAGE_FAULT; break;
}
if (!(vcpu->arch.fault_dsisr & (DSISR_NOHPTE | DSISR_PROTFAULT))) {
kvmppc_core_queue_data_storage(vcpu,
kvmppc_get_msr(vcpu) & SRR1_PREFIXED,
vcpu->arch.fault_dar, vcpu->arch.fault_dsisr);
r = RESUME_GUEST; break;
}
err = kvmppc_hpte_hv_fault(vcpu, vcpu->arch.fault_dar,
vsid, vcpu->arch.fault_dsisr, false); if (err == 0) {
r = RESUME_GUEST;
} elseif (err == -1) {
r = RESUME_PAGE_FAULT;
} else {
kvmppc_core_queue_inst_storage(vcpu,
err | (kvmppc_get_msr(vcpu) & SRR1_PREFIXED));
r = RESUME_GUEST;
} break;
}
/* *Thisoccursiftheguestexecutesanillegalinstruction. *Iftheguestdebugisdisabled,generateaprograminterrupt *totheguest.Ifguestdebugisenabled,weneedtocheck *whethertheinstructionisasoftwarebreakpointinstruction. *AccordinglyreturntoGuestorHost.
*/ case BOOK3S_INTERRUPT_H_EMUL_ASSIST: if (vcpu->arch.emul_inst != KVM_INST_FETCH_FAILED)
vcpu->arch.last_inst = kvmppc_need_byteswap(vcpu) ?
swab32(vcpu->arch.emul_inst) :
vcpu->arch.emul_inst; if (vcpu->guest_debug & KVM_GUESTDBG_USE_SW_BP) {
r = kvmppc_emulate_debug_inst(vcpu);
} else {
kvmppc_core_queue_program(vcpu, SRR1_PROGILL |
(kvmppc_get_msr(vcpu) & SRR1_PREFIXED));
r = RESUME_GUEST;
} break;
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM case BOOK3S_INTERRUPT_HV_SOFTPATCH: /* *ThisoccursforvariousTM-relatedinstructionsthat *weneedtoemulateonPOWER9DD2.2.Wehavealready *handledthecaseswheretheguestwasinreal-suspend *modeandwastransitioningtotransactionalstate.
*/
r = kvmhv_p9_tm_emulation(vcpu); if (r != -1) break;
fallthrough; /* go to facility unavailable handler */ #endif
/* *Thisoccursiftheguest(kerneloruserspace),doessomethingthat *isprohibitedbyHFSCR. *OnPOWER9,thiscouldbeadoorbellinstructionthatweneed *toemulate. *Otherwise,wejustgenerateaprograminterrupttotheguest.
*/ case BOOK3S_INTERRUPT_H_FAC_UNAVAIL: {
u64 cause = kvmppc_get_hfscr_hv(vcpu) >> 56;
r = EMULATE_FAIL; if (cpu_has_feature(CPU_FTR_ARCH_300)) { switch (cause) { case FSCR_MSGP_LG:
r = kvmppc_emulate_doorbell_instr(vcpu); break; case FSCR_PM_LG:
r = kvmppc_pmu_unavailable(vcpu); break; case FSCR_EBB_LG:
r = kvmppc_ebb_unavailable(vcpu); break; case FSCR_TM_LG:
r = kvmppc_tm_unavailable(vcpu); break; default: break;
}
} if (r == EMULATE_FAIL) {
kvmppc_core_queue_program(vcpu, SRR1_PROGILL |
(kvmppc_get_msr(vcpu) & SRR1_PREFIXED));
r = RESUME_GUEST;
} break;
}
case BOOK3S_INTERRUPT_HV_RM_HARD:
r = RESUME_PASSTHROUGH; break; default:
kvmppc_dump_regs(vcpu);
printk(KERN_EMERG "trap=0x%x | pc=0x%lx | msr=0x%llx\n",
vcpu->arch.trap, kvmppc_get_pc(vcpu),
__kvmppc_get_msr_hv(vcpu));
run->hw.hardware_exit_reason = vcpu->arch.trap;
r = RESUME_HOST; break;
}
return r;
}
staticint kvmppc_handle_nested_exit(struct kvm_vcpu *vcpu)
{ int r; int srcu_idx;
vcpu->stat.sum_exits++;
/* *Thiscanhappenifaninterruptoccursinthelaststages *ofguestentryorthefirststagesofguestexit(i.e.after *settingpaca->kvm_hstate.in_guesttoKVM_GUEST_MODE_GUEST_HV *andbeforesettingittoKVM_GUEST_MODE_HOST_HV). *Thatcanhappenduetoabug,orduetoamachinecheck *occurringatjustthewrongtime.
*/ if (__kvmppc_get_msr_hv(vcpu) & MSR_HV) {
pr_emerg("KVM trap in HV mode while nested!\n");
pr_emerg("trap=0x%x | pc=0x%lx | msr=0x%llx\n",
vcpu->arch.trap, kvmppc_get_pc(vcpu),
__kvmppc_get_msr_hv(vcpu));
kvmppc_dump_regs(vcpu); return RESUME_HOST;
} switch (vcpu->arch.trap) { /* We're good on these - the host merely wanted to get our attention */ case BOOK3S_INTERRUPT_HV_DECREMENTER:
vcpu->stat.dec_exits++;
r = RESUME_GUEST; break; case BOOK3S_INTERRUPT_EXTERNAL:
vcpu->stat.ext_intr_exits++;
r = RESUME_HOST; break; case BOOK3S_INTERRUPT_H_DOORBELL: case BOOK3S_INTERRUPT_H_VIRT:
vcpu->stat.ext_intr_exits++;
r = RESUME_GUEST; break; /* These need to go to the nested HV */ case BOOK3S_INTERRUPT_NESTED_HV_DECREMENTER:
vcpu->arch.trap = BOOK3S_INTERRUPT_HV_DECREMENTER;
vcpu->stat.dec_exits++;
r = RESUME_HOST; break; /* SR/HMI/PMI are HV interrupts that host has handled. Resume guest.*/ case BOOK3S_INTERRUPT_HMI: case BOOK3S_INTERRUPT_PERFMON: case BOOK3S_INTERRUPT_SYSTEM_RESET:
r = RESUME_GUEST; break; case BOOK3S_INTERRUPT_MACHINE_CHECK:
{ static DEFINE_RATELIMIT_STATE(rs, DEFAULT_RATELIMIT_INTERVAL,
DEFAULT_RATELIMIT_BURST); /* Pass the machine check to the L1 guest */
r = RESUME_HOST; /* Print the MCE event to host console. */ if (__ratelimit(&rs))
machine_check_print_event_info(&vcpu->arch.mce_evt, false, true); break;
} /* *Wegetthesenexttwoiftheguestaccessesapagewhichitthinks *ithasmappedbutwhichisnotactuallypresent,eitherbecause *itisforanemulatedI/Odeviceorbecausethecorresonding *hostpagehasbeenpagedout.
*/ case BOOK3S_INTERRUPT_H_DATA_STORAGE:
srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
r = kvmhv_nested_page_fault(vcpu);
srcu_read_unlock(&vcpu->kvm->srcu, srcu_idx); break; case BOOK3S_INTERRUPT_H_INST_STORAGE:
vcpu->arch.fault_dar = kvmppc_get_pc(vcpu);
vcpu->arch.fault_dsisr = kvmppc_get_msr(vcpu) &
DSISR_SRR1_MATCH_64S; if (__kvmppc_get_msr_hv(vcpu) & HSRR1_HISI_WRITE)
vcpu->arch.fault_dsisr |= DSISR_ISSTORE;
srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
r = kvmhv_nested_page_fault(vcpu);
srcu_read_unlock(&vcpu->kvm->srcu, srcu_idx); break;
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM case BOOK3S_INTERRUPT_HV_SOFTPATCH: /* *ThisoccursforvariousTM-relatedinstructionsthat *weneedtoemulateonPOWER9DD2.2.Wehavealready *handledthecaseswheretheguestwasinreal-suspend *modeandwastransitioningtotransactionalstate.
*/
r = kvmhv_p9_tm_emulation(vcpu); if (r != -1) break;
fallthrough; /* go to facility unavailable handler */ #endif
case BOOK3S_INTERRUPT_H_FAC_UNAVAIL:
r = RESUME_HOST; break;
case BOOK3S_INTERRUPT_HV_RM_HARD:
vcpu->arch.trap = 0;
r = RESUME_GUEST; if (!xics_on_xive())
kvmppc_xics_rm_complete(vcpu, 0); break; case BOOK3S_INTERRUPT_SYSCALL:
{ unsignedlong req = kvmppc_get_gpr(vcpu, 3);
/* *TheH_RPT_INVALIDATEhcallsissuedbynested *guestsforprocess-scopedinvalidationswhen *GTSE=0,arehandledhereinL0.
*/ if (req == H_RPT_INVALIDATE) {
r = kvmppc_nested_h_rpt_invalidate(vcpu); break;
}
r = RESUME_HOST; break;
} default:
r = RESUME_HOST; break;
}
return r;
}
staticint kvm_arch_vcpu_ioctl_get_sregs_hv(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs)
{ int i;
memset(sregs, 0, sizeof(struct kvm_sregs));
sregs->pvr = vcpu->arch.pvr; for (i = 0; i < vcpu->arch.slb_max; i++) {
sregs->u.s.ppc64.slb[i].slbe = vcpu->arch.slb[i].orige;
sregs->u.s.ppc64.slb[i].slbv = vcpu->arch.slb[i].origv;
}
return0;
}
staticint kvm_arch_vcpu_ioctl_set_sregs_hv(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs)
{ int i, j;
/* Only accept the same PVR as the host's, since we can't spoof it */ if (sregs->pvr != vcpu->arch.pvr) return -EINVAL;
j = 0; for (i = 0; i < vcpu->arch.slb_nr; i++) { if (sregs->u.s.ppc64.slb[i].slbe & SLB_ESID_V) {
vcpu->arch.slb[j].orige = sregs->u.s.ppc64.slb[i].slbe;
vcpu->arch.slb[j].origv = sregs->u.s.ppc64.slb[i].slbv;
++j;
}
}
vcpu->arch.slb_max = j;
return0;
}
/* *EnforcelimitsonguestLPCRvaluesbasedonhardwareavailability, *guestconfiguration,andpossiblyhypervisorsupportandsecurity *concerns.
*/ unsignedlong kvmppc_filter_lpcr_hv(struct kvm *kvm, unsignedlong lpcr)
{ /* LPCR_TC only applies to HPT guests */ if (kvm_is_radix(kvm))
lpcr &= ~LPCR_TC;
/* On POWER8 and above, userspace can modify AIL */ if (!cpu_has_feature(CPU_FTR_ARCH_207S))
lpcr &= ~LPCR_AIL; if ((lpcr & LPCR_AIL) != LPCR_AIL_3)
lpcr &= ~LPCR_AIL; /* LPCR[AIL]=1/2 is disallowed */ /* *OnsomePOWER9sweforceAILoffforradixgueststoprevent *executinginMSR[HV]=1modewiththeMMUenabledandPIDRsetto *guest,whichcanresultinQ0translationswithLPID=0PID=PIDRto *becached,whichthehostTLBmanagementdoesnotexpect.
*/ if (kvm_is_radix(kvm) && cpu_has_feature(CPU_FTR_P9_RADIX_PREFETCH_BUG))
lpcr &= ~LPCR_AIL;
/* *OnPOWER9,allowuserspacetoenablelargedecrementerforthe *guest,whetherornotthehosthasitenabled.
*/ if (!cpu_has_feature(CPU_FTR_ARCH_300))
lpcr &= ~LPCR_LD;
/* On POWER10 and later, allow prefixed instructions */ if (cpu_has_feature(CPU_FTR_ARCH_31))
kvmppc_set_hfscr_hv(vcpu, kvmppc_get_hfscr_hv(vcpu) | HFSCR_PREFIX);
if (cpu_has_feature(CPU_FTR_HVMODE)) {
kvmppc_set_hfscr_hv(vcpu, kvmppc_get_hfscr_hv(vcpu) & mfspr(SPRN_HFSCR));
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM if (cpu_has_feature(CPU_FTR_P9_TM_HV_ASSIST))
kvmppc_set_hfscr_hv(vcpu, kvmppc_get_hfscr_hv(vcpu) | HFSCR_TM); #endif
} if (cpu_has_feature(CPU_FTR_TM_COMP))
vcpu->arch.hfscr |= HFSCR_TM;
/* Ensure the thread won't go into the kernel if it wakes */
tpaca->kvm_hstate.kvm_vcpu = NULL;
tpaca->kvm_hstate.kvm_vcore = NULL;
tpaca->kvm_hstate.napping = 0;
smp_wmb();
tpaca->kvm_hstate.hwthread_req = 1;
staticvoid radix_flush_cpu(struct kvm *kvm, int cpu, struct kvm_vcpu *vcpu)
{ struct kvm_nested_guest *nested = vcpu->arch.nested;
cpumask_t *need_tlb_flush; int i;
if (nested)
need_tlb_flush = &nested->need_tlb_flush; else
need_tlb_flush = &kvm->arch.need_tlb_flush;
cpu = cpu_first_tlb_thread_sibling(cpu); for (i = cpu; i <= cpu_last_tlb_thread_sibling(cpu);
i += cpu_tlb_thread_sibling_step())
cpumask_set_cpu(i, need_tlb_flush);
cpu = vc->pcpu; if (vcpu) { if (vcpu->arch.timer_running) {
hrtimer_try_to_cancel(&vcpu->arch.dec_timer);
vcpu->arch.timer_running = 0;
}
cpu += vcpu->arch.ptid;
vcpu->cpu = vc->pcpu;
vcpu->arch.thread_cpu = cpu;
}
tpaca = paca_ptrs[cpu];
tpaca->kvm_hstate.kvm_vcpu = vcpu;
tpaca->kvm_hstate.ptid = cpu - vc->pcpu;
tpaca->kvm_hstate.fake_suspend = 0; /* Order stores to hstate.kvm_vcpu etc. before store to kvm_vcore */
smp_wmb();
tpaca->kvm_hstate.kvm_vcore = vc; if (cpu != smp_processor_id())
kvmppc_ipi_thread(cpu);
}
staticvoid kvmppc_wait_for_nap(int n_threads)
{ int cpu = smp_processor_id(); int i, loops;
if (n_threads <= 1) return; for (loops = 0; loops < 1000000; ++loops) { /* *Checkifallthreadsarefinished. *Wesetthevcorepointerwhenstartingathread *andthethreadclearsitwhenfinished,sowelook *foranythreadsthatstillhaveanon-NULLvcoreptr.
*/ for (i = 1; i < n_threads; ++i) if (paca_ptrs[cpu + i]->kvm_hstate.kvm_vcore) break; if (i == n_threads) {
HMT_medium(); return;
}
HMT_low();
}
HMT_medium(); for (i = 1; i < n_threads; ++i) if (paca_ptrs[cpu + i]->kvm_hstate.kvm_vcore)
pr_err("KVM: CPU %d seems to be stuck\n", cpu + i);
}
/* *Checkthatweareonthread0andthatanyotherthreadsin *thiscoreareoff-line.Thengrabthethreadssotheycan't *enterthekernel.
*/ staticint on_primary_thread(void)
{ int cpu = smp_processor_id(); int thr;
/* Are we on a primary subcore? */ if (cpu_thread_in_subcore(cpu)) return0;
thr = 0; while (++thr < threads_per_subcore) if (cpu_online(cpu + thr)) return0;
/* Grab all hw threads so they can't go into the kernel */ for (thr = 1; thr < threads_per_subcore; ++thr) { if (kvmppc_grab_hwthread(cpu + thr)) { /* Couldn't grab one; let the others go */ do {
kvmppc_release_hwthread(cpu + thr);
} while (--thr > 0); return0;
}
} return1;
}
/* *Thisstoresinformationaboutthevirtualcorescurrently *assignedtoaphysicalcore.
*/ struct core_info { int n_subcores; int max_subcore_threads; int total_threads; int subcore_threads[MAX_SUBCORES]; struct kvmppc_vcore *vc[MAX_SUBCORES];
};
staticbool subcore_config_ok(int n_subcores, int n_threads)
{ /* *POWER9"SMT4"coresarepermanentlyinwhatiseffectivelya4-way *split-coremode,withonethreadpersubcore.
*/ if (cpu_has_feature(CPU_FTR_ARCH_300)) return n_subcores <= 4 && n_threads == 1;
/* On POWER8, can only dynamically split if unsplit to begin with */ if (n_subcores > 1 && threads_per_subcore < MAX_SMT_THREADS) returnfalse; if (n_subcores > MAX_SUBCORES) returnfalse; if (n_subcores > 1) { if (!(dynamic_mt_modes & 2))
n_subcores = 4; if (n_subcores > 2 && !(dynamic_mt_modes & 4)) returnfalse;
}
/* *Hard-disableinterrupts,andcheckreschedflagandsignals. *Ifweneedtorescheduleordeliverasignal,cleanup *andreturnwithoutgoingintotheguest(s). *Ifthemmu_readyflaghasbeencleared,don'tgointothe *guestbecausethatmeansaHPTresizeoperationisinprogress.
*/
local_irq_disable();
hard_irq_disable(); if (lazy_irq_pending() || need_resched() ||
recheck_signals_and_mmu(&core_info)) {
local_irq_enable();
vc->vcore_state = VCORE_INACTIVE; /* Unlock all except the primary vcore */ for (sub = 1; sub < core_info.n_subcores; ++sub) {
pvc = core_info.vc[sub]; /* Put back on to the preempted vcores list */
kvmppc_vcore_preempt(pvc);
spin_unlock(&pvc->lock);
} for (i = 0; i < controlled_threads; ++i)
kvmppc_release_hwthread(pcpu + i); return;
}
/* Let secondaries go back to the offline loop */ for (i = 0; i < controlled_threads; ++i) {
kvmppc_release_hwthread(pcpu + i); if (sip && sip->napped[i])
kvmppc_ipi_thread(pcpu + i);
}
spin_unlock(&vc->lock);
/* make sure updates to secondary vcpu structs are visible now */
smp_mb();
preempt_enable();
for (sub = 0; sub < core_info.n_subcores; ++sub) {
pvc = core_info.vc[sub];
post_guest_process(pvc, pvc == vc);
}
if (rc != H_SUCCESS) {
pr_err("KVM Guest Run VCPU hcall failed\n"); if (rc == H_INVALID_ELEMENT_ID)
pr_err("KVM: Guest Run VCPU invalid element id at %ld\n", i); elseif (rc == H_INVALID_ELEMENT_SIZE)
pr_err("KVM: Guest Run VCPU invalid element size at %ld\n", i); elseif (rc == H_INVALID_ELEMENT_VALUE)
pr_err("KVM: Guest Run VCPU invalid element value at %ld\n", i); return -EINVAL;
}
accumulate_time(vcpu, &vcpu->arch.guest_exit);
dec = mfspr(SPRN_DEC); if (!(lpcr & LPCR_LD)) /* Sign extend if not using large decrementer */
dec = (s32) dec;
*tb = mftb();
vcpu->arch.dec_expires = dec + (*tb + kvmppc_get_tb_offset(vcpu));
timer_rearm_host_dec(*tb);
restore_p9_host_os_sprs(vcpu, &host_os_sprs); if (vcpu->arch.psscr != host_psscr)
mtspr(SPRN_PSSCR_PR, host_psscr);
next_timer = timer_get_next_tb(); if (*tb >= next_timer) return BOOK3S_INTERRUPT_HV_DECREMENTER; if (next_timer < time_limit)
time_limit = next_timer; elseif (*tb >= time_limit) /* nested time limit */ return BOOK3S_INTERRUPT_NESTED_HV_DECREMENTER;
vcpu->arch.ceded = 0;
vcpu_vpa_increment_dispatch(vcpu);
if (kvmhv_on_pseries()) { if (kvmhv_is_nestedv1())
trap = kvmhv_vcpu_entry_p9_nested(vcpu, time_limit, lpcr, tb); else
trap = kvmhv_vcpu_entry_nestedv2(vcpu, time_limit, lpcr, tb);
/* H_CEDE has to be handled now, not later */ if (trap == BOOK3S_INTERRUPT_SYSCALL && !nested &&
kvmppc_get_gpr(vcpu, 3) == H_CEDE) {
kvmppc_cede(vcpu);
kvmppc_set_gpr(vcpu, 3, 0);
trap = 0;
}
/* Poll for pending exceptions and ceded state */
cur = start_poll = ktime_get(); if (vc->halt_poll_ns) {
ktime_t stop = ktime_add_ns(start_poll, vc->halt_poll_ns);
++vc->runner->stat.generic.halt_attempted_poll;
if (!do_sleep) {
++vc->runner->stat.generic.halt_successful_poll; goto out;
}
}
prepare_to_rcuwait(&vc->wait);
set_current_state(TASK_INTERRUPTIBLE); if (kvmppc_vcore_check_block(vc)) {
finish_rcuwait(&vc->wait);
do_sleep = 0; /* If we polled, count this as a successful poll */ if (vc->halt_poll_ns)
++vc->runner->stat.generic.halt_successful_poll; goto out;
}
/* Adjust poll time */ if (halt_poll_ns) { if (block_ns <= vc->halt_poll_ns)
; /* We slept and blocked for longer than the max halt time */ elseif (vc->halt_poll_ns && block_ns > halt_poll_ns)
shrink_halt_poll_ns(vc); /* We slept and our poll time is too small */ elseif (vc->halt_poll_ns < halt_poll_ns &&
block_ns < halt_poll_ns)
grow_halt_poll_ns(vc); if (vc->halt_poll_ns > halt_poll_ns)
vc->halt_poll_ns = halt_poll_ns;
} else
vc->halt_poll_ns = 0;
trace_kvmppc_vcore_wakeup(do_sleep, block_ns);
}
/* *Thisneverfailsforaradixguest,asnoneoftheoperationsitdoes *foraradixguestcanfailorhaveawaytoreportfailure.
*/ staticint kvmhv_setup_mmu(struct kvm_vcpu *vcpu)
{ int r = 0; struct kvm *kvm = vcpu->kvm;
mutex_lock(&kvm->arch.mmu_setup_lock); if (!kvm->arch.mmu_ready) { if (!kvm_is_radix(kvm))
r = kvmppc_hv_setup_htab_rma(vcpu); if (!r) { if (cpu_has_feature(CPU_FTR_ARCH_300))
kvmppc_setup_partition_table(kvm);
kvm->arch.mmu_ready = 1;
}
}
mutex_unlock(&kvm->arch.mmu_setup_lock); return r;
}
staticint kvmppc_run_vcpu(struct kvm_vcpu *vcpu)
{ struct kvm_run *run = vcpu->run; int n_ceded, i, r; struct kvmppc_vcore *vc; struct kvm_vcpu *v;
while (vcpu->arch.state == KVMPPC_VCPU_RUNNABLE &&
!signal_pending(current)) { /* See if the MMU is ready to go */ if (!vcpu->kvm->arch.mmu_ready) {
spin_unlock(&vc->lock);
r = kvmhv_setup_mmu(vcpu);
spin_lock(&vc->lock); if (r) {
run->exit_reason = KVM_EXIT_FAIL_ENTRY;
run->fail_entry.
hardware_entry_failure_reason = 0;
vcpu->arch.ret = r; break;
}
}
if (vc->vcore_state == VCORE_PREEMPT && vc->runner == NULL)
kvmppc_vcore_end_preempt(vc);
if (vc->n_runnable && vc->vcore_state == VCORE_INACTIVE) { /* Wake up some vcpu to run the core */
i = -1;
v = next_runnable_thread(vc, &i);
wake_up(&v->arch.cpu_run);
}
/* See if the MMU is ready to go */ if (unlikely(!kvm->arch.mmu_ready)) {
r = kvmhv_setup_mmu(vcpu); if (r) {
run->exit_reason = KVM_EXIT_FAIL_ENTRY;
run->fail_entry.hardware_entry_failure_reason = 0;
vcpu->arch.ret = r; return r;
}
}
if (need_resched())
cond_resched();
kvmppc_update_vpas(vcpu);
preempt_disable();
pcpu = smp_processor_id(); if (kvm_is_radix(kvm))
kvmppc_prepare_radix_vcpu(vcpu, pcpu);
/* flags save not required, but irq_pmu has no disable/enable API */
powerpc_local_irq_pmu_save(flags);
vcpu->arch.state = KVMPPC_VCPU_RUNNABLE;
if (signal_pending(current)) goto sigpend; if (need_resched() || !kvm->arch.mmu_ready) goto out;
trace_kvm_guest_exit(vcpu);
r = RESUME_GUEST; if (trap) { if (!nested)
r = kvmppc_handle_exit_hv(vcpu, current); else
r = kvmppc_handle_nested_exit(vcpu);
}
vcpu->arch.ret = r;
if (is_kvmppc_resume_guest(r) && !kvmppc_vcpu_check_block(vcpu)) {
kvmppc_set_timer(vcpu);
prepare_to_rcuwait(wait); for (;;) {
set_current_state(TASK_INTERRUPTIBLE); if (signal_pending(current)) {
vcpu->stat.signal_exits++;
run->exit_reason = KVM_EXIT_INTR;
vcpu->arch.ret = -EINTR; break;
}
staticint kvmppc_vcpu_run_hv(struct kvm_vcpu *vcpu)
{ struct kvm_run *run = vcpu->run; int r; int srcu_idx; struct kvm *kvm; unsignedlong msr;
start_timing(vcpu, &vcpu->arch.vcpu_entry);
if (!vcpu->arch.sane) {
run->exit_reason = KVM_EXIT_INTERNAL_ERROR; return -EINVAL;
}
/* No need to go into the guest when all we'll do is come back out */ if (signal_pending(current)) {
run->exit_reason = KVM_EXIT_INTR; return -EINTR;
}
do {
accumulate_time(vcpu, &vcpu->arch.guest_entry); if (cpu_has_feature(CPU_FTR_ARCH_300))
r = kvmhv_run_single_vcpu(vcpu, ~(u64)0,
vcpu->arch.vcore->lpcr); else
r = kvmppc_run_vcpu(vcpu);
if (run->exit_reason == KVM_EXIT_PAPR_HCALL) {
accumulate_time(vcpu, &vcpu->arch.hcall);
if (!kvmhv_is_nestedv2() && WARN_ON_ONCE(__kvmppc_get_msr_hv(vcpu) & MSR_PR)) { /* *Theseshouldhavebeencaughtreflected *intotheguestbynow.Finalsanitycheck: *don'tallowuserspacetoexecutehcallsin *thehypervisor.
*/
r = RESUME_GUEST; continue;
}
trace_kvm_hcall_enter(vcpu);
r = kvmppc_pseries_do_hcall(vcpu);
trace_kvm_hcall_exit(vcpu, r);
kvmppc_core_prepare_to_enter(vcpu);
} elseif (r == RESUME_PAGE_FAULT) {
accumulate_time(vcpu, &vcpu->arch.pg_fault);
srcu_idx = srcu_read_lock(&kvm->srcu);
r = kvmppc_book3s_hv_page_fault(vcpu,
vcpu->arch.fault_dar, vcpu->arch.fault_dsisr);
srcu_read_unlock(&kvm->srcu, srcu_idx);
} elseif (r == RESUME_PASSTHROUGH) { if (WARN_ON(xics_on_xive()))
r = H_SUCCESS; else
r = kvmppc_xics_rm_complete(vcpu, 0);
}
} while (is_kvmppc_resume_guest(r));
accumulate_time(vcpu, &vcpu->arch.vcpu_exit);
/* POWER7, 8 and 9 all have 1T segments and 32-entry SLB */
info->flags = KVM_PPC_PAGE_SIZES_REAL | KVM_PPC_1T_SEGMENTS;
info->slb_size = 32;
/* We only support these sizes for now, and no muti-size segments */
sps = &info->sps[0];
kvmppc_add_seg_page_size(&sps, 12, 0);
kvmppc_add_seg_page_size(&sps, 16, SLB_VSID_L | SLB_VSID_LP_01);
kvmppc_add_seg_page_size(&sps, 24, SLB_VSID_L);
/* If running as a nested hypervisor, we don't support HPT guests */ if (kvmhv_on_pseries())
info->flags |= KVM_PPC_NO_HASH;
r = -EINVAL; if (log->slot >= KVM_USER_MEM_SLOTS) goto out;
slots = kvm_memslots(kvm);
memslot = id_to_memslot(slots, log->slot);
r = -ENOENT; if (!memslot || !memslot->dirty_bitmap) goto out;
/* *UsesecondhalfofbitmapareabecausebothHPTandradix *accumulatebitsinthefirsthalf.
*/
n = kvm_dirty_bitmap_bytes(memslot);
buf = memslot->dirty_bitmap + n / sizeof(long);
memset(buf, 0, n);
if (kvm_is_radix(kvm))
r = kvmppc_hv_get_dirty_log_radix(kvm, memslot, buf); else
r = kvmppc_hv_get_dirty_log_hpt(kvm, memslot, buf); if (r) goto out;
/* *Weaccumulatedirtybitsinthefirsthalfofthe *memslot'sdirty_bitmaparea,forwhenpagesarepaged *outormodifiedbythehostdirectly.Pickupthese *bitsandaddthemtothemap.
*/
p = memslot->dirty_bitmap; for (i = 0; i < n / sizeof(long); ++i)
buf[i] |= xchg(&p[i], 0);
/* Harvest dirty bits from VPA and DTL updates */ /* Note: we never modify the SLB shadow buffer areas */
kvm_for_each_vcpu(i, vcpu, kvm) {
spin_lock(&vcpu->arch.vpa_update_lock);
kvmppc_harvest_vpa_dirty(&vcpu->arch.vpa, memslot, buf);
kvmppc_harvest_vpa_dirty(&vcpu->arch.dtl, memslot, buf);
spin_unlock(&vcpu->arch.vpa_update_lock);
}
r = -EFAULT; if (copy_to_user(log->dirty_bitmap, buf, n)) goto out;
r = 0;
out:
mutex_unlock(&kvm->slots_lock); return r;
}
/* Allocate hashed page table (if not done already) and reset it */ if (!kvm->arch.hpt.virt) { int order = KVM_DEFAULT_HPT_ORDER; struct kvm_hpt_info info;
err = kvmppc_allocate_hpt(&info, order); /* If we get here, it means userspace didn't specify a *sizeexplicitly.So,trysuccessivelysmaller
* sizes if the default failed. */ while ((err == -ENOMEM) && --order >= PPC_MIN_HPT_ORDER)
err = kvmppc_allocate_hpt(&info, order);
/* Look up the memslot for guest physical address 0 */
srcu_idx = srcu_read_lock(&kvm->srcu);
memslot = gfn_to_memslot(kvm, 0);
/* We must have some memory at 0 by now */
err = -EINVAL; if (!memslot || (memslot->flags & KVM_MEMSLOT_INVALID)) goto out_srcu;
/* Look up the VMA for the start of this memory slot */
hva = memslot->userspace_addr;
mmap_read_lock(kvm->mm);
vma = vma_lookup(kvm->mm, hva); if (!vma || (vma->vm_flags & VM_IO)) goto up_out;
psize = vma_kernel_pagesize(vma);
mmap_read_unlock(kvm->mm);
/* We can handle 4k, 64k or 16M pages in the VRMA */ if (psize >= 0x1000000)
psize = 0x1000000; elseif (psize >= 0x10000)
psize = 0x10000; else
psize = 0x1000;
porder = __ilog2(psize);
senc = slb_pgsize_encoding(psize);
kvm->arch.vrma_slb_v = senc | SLB_VSID_B_1T |
(VRMA_VSID << SLB_VSID_SHIFT_1T); /* Create HPTEs in the hash page table for the VRMA */
kvmppc_map_vrma(vcpu, memslot, porder);
/* Update VRMASD field in the LPCR */ if (!cpu_has_feature(CPU_FTR_ARCH_300)) { /* the -4 is to account for senc values starting at 0x10 */
lpcr = senc << (LPCR_VRMASD_SH - 4);
kvmppc_update_lpcr(kvm, lpcr, LPCR_VRMASD);
}
/* Order updates to kvm->arch.lpcr etc. vs. mmu_ready */
smp_wmb();
err = 0;
out_srcu:
srcu_read_unlock(&kvm->srcu, srcu_idx);
out: return err;
switch (rc) { case H_PARAMETER: case H_FUNCTION: case H_STATE: return -EINVAL; case H_NOT_ENOUGH_RESOURCES: case H_ABORTED: return -ENOMEM; case H_AUTHORITY: return -EPERM; case H_NOT_AVAILABLE: return -EBUSY;
}
kvm->arch.lpid = guest_id;
}
/* *Sincewedon'tflushtheTLBwhentearingdownaVM, *andthislpidmighthavepreviouslybeenused, *makesureweflushoneachcorebeforerunningthenewVM. *OnPOWER9,thetlbieinmmu_partition_table_set_entry() *doesthisflushforus.
*/ if (!cpu_has_feature(CPU_FTR_ARCH_300))
cpumask_setall(&kvm->arch.need_tlb_flush);
/* Start out with the default set of hcalls enabled */
memcpy(kvm->arch.enabled_hcalls, default_enabled_hcalls, sizeof(kvm->arch.enabled_hcalls));
if (!cpu_has_feature(CPU_FTR_ARCH_300))
kvm->arch.host_sdr1 = mfspr(SPRN_SDR1);
for (i = 0; i < KVM_MAX_VCORES; ++i)
kfree(kvm->arch.vcores[i]);
kvm->arch.online_vcores = 0;
}
staticvoid kvmppc_core_destroy_vm_hv(struct kvm *kvm)
{ if (!cpu_has_feature(CPU_FTR_ARCH_300))
kvm_hv_vm_deactivated();
kvmppc_free_vcores(kvm);
if (kvm_is_radix(kvm))
kvmppc_free_radix(kvm); else
kvmppc_free_hpt(&kvm->arch.hpt);
/* Perform global invalidation and return lpid to the pool */ if (cpu_has_feature(CPU_FTR_ARCH_300)) { if (nesting_enabled(kvm))
kvmhv_release_all_nested(kvm);
kvm->arch.process_table = 0; if (kvm->arch.secure_guest)
uv_svm_terminate(kvm->arch.lpid); if (!kvmhv_is_nestedv2())
kvmhv_set_ptbl_entry(kvm->arch.lpid, 0, 0);
}
/* We don't need to emulate any privileged instructions or dcbz */ staticint kvmppc_core_emulate_op_hv(struct kvm_vcpu *vcpu, unsignedint inst, int *advance)
{ return EMULATE_FAIL;
}
if (xics_on_xive())
rc = kvmppc_xive_set_mapped(kvm, guest_gsi, host_irq); else
kvmppc_xics_set_mapped(kvm, guest_gsi, irq_map->r_hwirq); if (rc)
irq_map->r_hwirq = 0;
mutex_unlock(&kvm->lock);
return0;
}
staticint kvmppc_clr_passthru_irq(struct kvm *kvm, int host_irq, int guest_gsi)
{ struct irq_desc *desc; struct kvmppc_passthru_irqmap *pimap; int i, rc = 0;
if (!kvm_irq_bypass) return0;
desc = irq_to_desc(host_irq); if (!desc) return -EIO;
mutex_lock(&kvm->lock); if (!kvm->arch.pimap) goto unlock;
pimap = kvm->arch.pimap;
for (i = 0; i < pimap->n_mapped; i++) { if (guest_gsi == pimap->mapped[i].v_hwirq) break;
}
if (i == pimap->n_mapped) {
mutex_unlock(&kvm->lock); return -ENODEV;
}
staticvoid init_default_hcalls(void)
{ int i; unsignedint hcall;
for (i = 0; default_hcall_list[i]; ++i) {
hcall = default_hcall_list[i];
WARN_ON(!kvmppc_hcall_impl_hv(hcall));
__set_bit(hcall / 4, default_enabled_hcalls);
}
}
staticint kvmhv_configure_mmu(struct kvm *kvm, struct kvm_ppc_mmuv3_cfg *cfg)
{ unsignedlong lpcr; int radix; int err;
/* If not on a POWER9, reject it */ if (!cpu_has_feature(CPU_FTR_ARCH_300)) return -ENODEV;
/* If any unknown flags set, reject it */ if (cfg->flags & ~(KVM_PPC_MMUV3_RADIX | KVM_PPC_MMUV3_GTSE)) return -EINVAL;
/* GR (guest radix) bit in process_table field must match */
radix = !!(cfg->flags & KVM_PPC_MMUV3_RADIX); if (!!(cfg->process_table & PATB_GR) != radix) return -EINVAL;
/* Process table size field must be reasonable, i.e. <= 24 */ if ((cfg->process_table & PRTS_MASK) > 24) return -EINVAL;
/* We can change a guest to/from radix now, if the host is radix */ if (radix && !radix_enabled()) return -EINVAL;
/* If we're a nested hypervisor, we currently only support radix */ if (kvmhv_on_pseries() && !radix) return -EINVAL;
mutex_lock(&kvm->arch.mmu_setup_lock); if (radix != kvm_is_radix(kvm)) { if (kvm->arch.mmu_ready) {
kvm->arch.mmu_ready = 0; /* order mmu_ready vs. vcpus_running */
smp_mb(); if (atomic_read(&kvm->arch.vcpus_running)) {
kvm->arch.mmu_ready = 1;
err = -EBUSY; goto out_unlock;
}
} if (radix)
err = kvmppc_switch_mmu_to_radix(kvm); else
err = kvmppc_switch_mmu_to_hpt(kvm); if (err) goto out_unlock;
}
module_init(kvmppc_book3s_init_hv);
module_exit(kvmppc_book3s_exit_hv);
MODULE_DESCRIPTION("KVM on Book3S (POWER8 and later) in hypervisor mode");
MODULE_LICENSE("GPL");
MODULE_ALIAS_MISCDEV(KVM_MINOR);
MODULE_ALIAS("devname:kvm");
Messung V0.5 in Prozent
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.334Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-09-28)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.