|
@@ -30,6 +30,7 @@
|
|
#include <linux/cpumask.h>
|
|
#include <linux/cpumask.h>
|
|
#include <linux/spinlock.h>
|
|
#include <linux/spinlock.h>
|
|
#include <linux/page-flags.h>
|
|
#include <linux/page-flags.h>
|
|
|
|
+#include <linux/srcu.h>
|
|
|
|
|
|
#include <asm/reg.h>
|
|
#include <asm/reg.h>
|
|
#include <asm/cputable.h>
|
|
#include <asm/cputable.h>
|
|
@@ -46,6 +47,7 @@
|
|
#include <asm/page.h>
|
|
#include <asm/page.h>
|
|
#include <asm/hvcall.h>
|
|
#include <asm/hvcall.h>
|
|
#include <asm/switch_to.h>
|
|
#include <asm/switch_to.h>
|
|
|
|
+#include <asm/smp.h>
|
|
#include <linux/gfp.h>
|
|
#include <linux/gfp.h>
|
|
#include <linux/vmalloc.h>
|
|
#include <linux/vmalloc.h>
|
|
#include <linux/highmem.h>
|
|
#include <linux/highmem.h>
|
|
@@ -55,25 +57,77 @@
|
|
/* #define EXIT_DEBUG_SIMPLE */
|
|
/* #define EXIT_DEBUG_SIMPLE */
|
|
/* #define EXIT_DEBUG_INT */
|
|
/* #define EXIT_DEBUG_INT */
|
|
|
|
|
|
|
|
+/* Used to indicate that a guest page fault needs to be handled */
|
|
|
|
+#define RESUME_PAGE_FAULT (RESUME_GUEST | RESUME_FLAG_ARCH1)
|
|
|
|
+
|
|
|
|
+/* Used as a "null" value for timebase values */
|
|
|
|
+#define TB_NIL (~(u64)0)
|
|
|
|
+
|
|
static void kvmppc_end_cede(struct kvm_vcpu *vcpu);
|
|
static void kvmppc_end_cede(struct kvm_vcpu *vcpu);
|
|
static int kvmppc_hv_setup_htab_rma(struct kvm_vcpu *vcpu);
|
|
static int kvmppc_hv_setup_htab_rma(struct kvm_vcpu *vcpu);
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * We use the vcpu_load/put functions to measure stolen time.
|
|
|
|
+ * Stolen time is counted as time when either the vcpu is able to
|
|
|
|
+ * run as part of a virtual core, but the task running the vcore
|
|
|
|
+ * is preempted or sleeping, or when the vcpu needs something done
|
|
|
|
+ * in the kernel by the task running the vcpu, but that task is
|
|
|
|
+ * preempted or sleeping. Those two things have to be counted
|
|
|
|
+ * separately, since one of the vcpu tasks will take on the job
|
|
|
|
+ * of running the core, and the other vcpu tasks in the vcore will
|
|
|
|
+ * sleep waiting for it to do that, but that sleep shouldn't count
|
|
|
|
+ * as stolen time.
|
|
|
|
+ *
|
|
|
|
+ * Hence we accumulate stolen time when the vcpu can run as part of
|
|
|
|
+ * a vcore using vc->stolen_tb, and the stolen time when the vcpu
|
|
|
|
+ * needs its task to do other things in the kernel (for example,
|
|
|
|
+ * service a page fault) in busy_stolen. We don't accumulate
|
|
|
|
+ * stolen time for a vcore when it is inactive, or for a vcpu
|
|
|
|
+ * when it is in state RUNNING or NOTREADY. NOTREADY is a bit of
|
|
|
|
+ * a misnomer; it means that the vcpu task is not executing in
|
|
|
|
+ * the KVM_VCPU_RUN ioctl, i.e. it is in userspace or elsewhere in
|
|
|
|
+ * the kernel. We don't have any way of dividing up that time
|
|
|
|
+ * between time that the vcpu is genuinely stopped, time that
|
|
|
|
+ * the task is actively working on behalf of the vcpu, and time
|
|
|
|
+ * that the task is preempted, so we don't count any of it as
|
|
|
|
+ * stolen.
|
|
|
|
+ *
|
|
|
|
+ * Updates to busy_stolen are protected by arch.tbacct_lock;
|
|
|
|
+ * updates to vc->stolen_tb are protected by the arch.tbacct_lock
|
|
|
|
+ * of the vcpu that has taken responsibility for running the vcore
|
|
|
|
+ * (i.e. vc->runner). The stolen times are measured in units of
|
|
|
|
+ * timebase ticks. (Note that the != TB_NIL checks below are
|
|
|
|
+ * purely defensive; they should never fail.)
|
|
|
|
+ */
|
|
|
|
+
|
|
void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
|
|
void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
|
|
{
|
|
{
|
|
struct kvmppc_vcore *vc = vcpu->arch.vcore;
|
|
struct kvmppc_vcore *vc = vcpu->arch.vcore;
|
|
|
|
|
|
- local_paca->kvm_hstate.kvm_vcpu = vcpu;
|
|
|
|
- local_paca->kvm_hstate.kvm_vcore = vc;
|
|
|
|
- if (vc->runner == vcpu && vc->vcore_state != VCORE_INACTIVE)
|
|
|
|
|
|
+ spin_lock(&vcpu->arch.tbacct_lock);
|
|
|
|
+ if (vc->runner == vcpu && vc->vcore_state != VCORE_INACTIVE &&
|
|
|
|
+ vc->preempt_tb != TB_NIL) {
|
|
vc->stolen_tb += mftb() - vc->preempt_tb;
|
|
vc->stolen_tb += mftb() - vc->preempt_tb;
|
|
|
|
+ vc->preempt_tb = TB_NIL;
|
|
|
|
+ }
|
|
|
|
+ if (vcpu->arch.state == KVMPPC_VCPU_BUSY_IN_HOST &&
|
|
|
|
+ vcpu->arch.busy_preempt != TB_NIL) {
|
|
|
|
+ vcpu->arch.busy_stolen += mftb() - vcpu->arch.busy_preempt;
|
|
|
|
+ vcpu->arch.busy_preempt = TB_NIL;
|
|
|
|
+ }
|
|
|
|
+ spin_unlock(&vcpu->arch.tbacct_lock);
|
|
}
|
|
}
|
|
|
|
|
|
void kvmppc_core_vcpu_put(struct kvm_vcpu *vcpu)
|
|
void kvmppc_core_vcpu_put(struct kvm_vcpu *vcpu)
|
|
{
|
|
{
|
|
struct kvmppc_vcore *vc = vcpu->arch.vcore;
|
|
struct kvmppc_vcore *vc = vcpu->arch.vcore;
|
|
|
|
|
|
|
|
+ spin_lock(&vcpu->arch.tbacct_lock);
|
|
if (vc->runner == vcpu && vc->vcore_state != VCORE_INACTIVE)
|
|
if (vc->runner == vcpu && vc->vcore_state != VCORE_INACTIVE)
|
|
vc->preempt_tb = mftb();
|
|
vc->preempt_tb = mftb();
|
|
|
|
+ if (vcpu->arch.state == KVMPPC_VCPU_BUSY_IN_HOST)
|
|
|
|
+ vcpu->arch.busy_preempt = mftb();
|
|
|
|
+ spin_unlock(&vcpu->arch.tbacct_lock);
|
|
}
|
|
}
|
|
|
|
|
|
void kvmppc_set_msr(struct kvm_vcpu *vcpu, u64 msr)
|
|
void kvmppc_set_msr(struct kvm_vcpu *vcpu, u64 msr)
|
|
@@ -142,6 +196,22 @@ static void init_vpa(struct kvm_vcpu *vcpu, struct lppaca *vpa)
|
|
vpa->yield_count = 1;
|
|
vpa->yield_count = 1;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int set_vpa(struct kvm_vcpu *vcpu, struct kvmppc_vpa *v,
|
|
|
|
+ unsigned long addr, unsigned long len)
|
|
|
|
+{
|
|
|
|
+ /* check address is cacheline aligned */
|
|
|
|
+ if (addr & (L1_CACHE_BYTES - 1))
|
|
|
|
+ return -EINVAL;
|
|
|
|
+ spin_lock(&vcpu->arch.vpa_update_lock);
|
|
|
|
+ if (v->next_gpa != addr || v->len != len) {
|
|
|
|
+ v->next_gpa = addr;
|
|
|
|
+ v->len = addr ? len : 0;
|
|
|
|
+ v->update_pending = 1;
|
|
|
|
+ }
|
|
|
|
+ spin_unlock(&vcpu->arch.vpa_update_lock);
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
/* Length for a per-processor buffer is passed in at offset 4 in the buffer */
|
|
/* Length for a per-processor buffer is passed in at offset 4 in the buffer */
|
|
struct reg_vpa {
|
|
struct reg_vpa {
|
|
u32 dummy;
|
|
u32 dummy;
|
|
@@ -317,10 +387,16 @@ static void kvmppc_update_vpa(struct kvm_vcpu *vcpu, struct kvmppc_vpa *vpap)
|
|
|
|
|
|
static void kvmppc_update_vpas(struct kvm_vcpu *vcpu)
|
|
static void kvmppc_update_vpas(struct kvm_vcpu *vcpu)
|
|
{
|
|
{
|
|
|
|
+ if (!(vcpu->arch.vpa.update_pending ||
|
|
|
|
+ vcpu->arch.slb_shadow.update_pending ||
|
|
|
|
+ vcpu->arch.dtl.update_pending))
|
|
|
|
+ return;
|
|
|
|
+
|
|
spin_lock(&vcpu->arch.vpa_update_lock);
|
|
spin_lock(&vcpu->arch.vpa_update_lock);
|
|
if (vcpu->arch.vpa.update_pending) {
|
|
if (vcpu->arch.vpa.update_pending) {
|
|
kvmppc_update_vpa(vcpu, &vcpu->arch.vpa);
|
|
kvmppc_update_vpa(vcpu, &vcpu->arch.vpa);
|
|
- init_vpa(vcpu, vcpu->arch.vpa.pinned_addr);
|
|
|
|
|
|
+ if (vcpu->arch.vpa.pinned_addr)
|
|
|
|
+ init_vpa(vcpu, vcpu->arch.vpa.pinned_addr);
|
|
}
|
|
}
|
|
if (vcpu->arch.dtl.update_pending) {
|
|
if (vcpu->arch.dtl.update_pending) {
|
|
kvmppc_update_vpa(vcpu, &vcpu->arch.dtl);
|
|
kvmppc_update_vpa(vcpu, &vcpu->arch.dtl);
|
|
@@ -332,24 +408,61 @@ static void kvmppc_update_vpas(struct kvm_vcpu *vcpu)
|
|
spin_unlock(&vcpu->arch.vpa_update_lock);
|
|
spin_unlock(&vcpu->arch.vpa_update_lock);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * Return the accumulated stolen time for the vcore up until `now'.
|
|
|
|
+ * The caller should hold the vcore lock.
|
|
|
|
+ */
|
|
|
|
+static u64 vcore_stolen_time(struct kvmppc_vcore *vc, u64 now)
|
|
|
|
+{
|
|
|
|
+ u64 p;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * If we are the task running the vcore, then since we hold
|
|
|
|
+ * the vcore lock, we can't be preempted, so stolen_tb/preempt_tb
|
|
|
|
+ * can't be updated, so we don't need the tbacct_lock.
|
|
|
|
+ * If the vcore is inactive, it can't become active (since we
|
|
|
|
+ * hold the vcore lock), so the vcpu load/put functions won't
|
|
|
|
+ * update stolen_tb/preempt_tb, and we don't need tbacct_lock.
|
|
|
|
+ */
|
|
|
|
+ if (vc->vcore_state != VCORE_INACTIVE &&
|
|
|
|
+ vc->runner->arch.run_task != current) {
|
|
|
|
+ spin_lock(&vc->runner->arch.tbacct_lock);
|
|
|
|
+ p = vc->stolen_tb;
|
|
|
|
+ if (vc->preempt_tb != TB_NIL)
|
|
|
|
+ p += now - vc->preempt_tb;
|
|
|
|
+ spin_unlock(&vc->runner->arch.tbacct_lock);
|
|
|
|
+ } else {
|
|
|
|
+ p = vc->stolen_tb;
|
|
|
|
+ }
|
|
|
|
+ return p;
|
|
|
|
+}
|
|
|
|
+
|
|
static void kvmppc_create_dtl_entry(struct kvm_vcpu *vcpu,
|
|
static void kvmppc_create_dtl_entry(struct kvm_vcpu *vcpu,
|
|
struct kvmppc_vcore *vc)
|
|
struct kvmppc_vcore *vc)
|
|
{
|
|
{
|
|
struct dtl_entry *dt;
|
|
struct dtl_entry *dt;
|
|
struct lppaca *vpa;
|
|
struct lppaca *vpa;
|
|
- unsigned long old_stolen;
|
|
|
|
|
|
+ unsigned long stolen;
|
|
|
|
+ unsigned long core_stolen;
|
|
|
|
+ u64 now;
|
|
|
|
|
|
dt = vcpu->arch.dtl_ptr;
|
|
dt = vcpu->arch.dtl_ptr;
|
|
vpa = vcpu->arch.vpa.pinned_addr;
|
|
vpa = vcpu->arch.vpa.pinned_addr;
|
|
- old_stolen = vcpu->arch.stolen_logged;
|
|
|
|
- vcpu->arch.stolen_logged = vc->stolen_tb;
|
|
|
|
|
|
+ now = mftb();
|
|
|
|
+ core_stolen = vcore_stolen_time(vc, now);
|
|
|
|
+ stolen = core_stolen - vcpu->arch.stolen_logged;
|
|
|
|
+ vcpu->arch.stolen_logged = core_stolen;
|
|
|
|
+ spin_lock(&vcpu->arch.tbacct_lock);
|
|
|
|
+ stolen += vcpu->arch.busy_stolen;
|
|
|
|
+ vcpu->arch.busy_stolen = 0;
|
|
|
|
+ spin_unlock(&vcpu->arch.tbacct_lock);
|
|
if (!dt || !vpa)
|
|
if (!dt || !vpa)
|
|
return;
|
|
return;
|
|
memset(dt, 0, sizeof(struct dtl_entry));
|
|
memset(dt, 0, sizeof(struct dtl_entry));
|
|
dt->dispatch_reason = 7;
|
|
dt->dispatch_reason = 7;
|
|
dt->processor_id = vc->pcpu + vcpu->arch.ptid;
|
|
dt->processor_id = vc->pcpu + vcpu->arch.ptid;
|
|
- dt->timebase = mftb();
|
|
|
|
- dt->enqueue_to_dispatch_time = vc->stolen_tb - old_stolen;
|
|
|
|
|
|
+ dt->timebase = now;
|
|
|
|
+ dt->enqueue_to_dispatch_time = stolen;
|
|
dt->srr0 = kvmppc_get_pc(vcpu);
|
|
dt->srr0 = kvmppc_get_pc(vcpu);
|
|
dt->srr1 = vcpu->arch.shregs.msr;
|
|
dt->srr1 = vcpu->arch.shregs.msr;
|
|
++dt;
|
|
++dt;
|
|
@@ -366,13 +479,16 @@ int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu)
|
|
unsigned long req = kvmppc_get_gpr(vcpu, 3);
|
|
unsigned long req = kvmppc_get_gpr(vcpu, 3);
|
|
unsigned long target, ret = H_SUCCESS;
|
|
unsigned long target, ret = H_SUCCESS;
|
|
struct kvm_vcpu *tvcpu;
|
|
struct kvm_vcpu *tvcpu;
|
|
|
|
+ int idx;
|
|
|
|
|
|
switch (req) {
|
|
switch (req) {
|
|
case H_ENTER:
|
|
case H_ENTER:
|
|
|
|
+ idx = srcu_read_lock(&vcpu->kvm->srcu);
|
|
ret = kvmppc_virtmode_h_enter(vcpu, kvmppc_get_gpr(vcpu, 4),
|
|
ret = kvmppc_virtmode_h_enter(vcpu, kvmppc_get_gpr(vcpu, 4),
|
|
kvmppc_get_gpr(vcpu, 5),
|
|
kvmppc_get_gpr(vcpu, 5),
|
|
kvmppc_get_gpr(vcpu, 6),
|
|
kvmppc_get_gpr(vcpu, 6),
|
|
kvmppc_get_gpr(vcpu, 7));
|
|
kvmppc_get_gpr(vcpu, 7));
|
|
|
|
+ srcu_read_unlock(&vcpu->kvm->srcu, idx);
|
|
break;
|
|
break;
|
|
case H_CEDE:
|
|
case H_CEDE:
|
|
break;
|
|
break;
|
|
@@ -429,6 +545,17 @@ static int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
|
|
case BOOK3S_INTERRUPT_PERFMON:
|
|
case BOOK3S_INTERRUPT_PERFMON:
|
|
r = RESUME_GUEST;
|
|
r = RESUME_GUEST;
|
|
break;
|
|
break;
|
|
|
|
+ case BOOK3S_INTERRUPT_MACHINE_CHECK:
|
|
|
|
+ /*
|
|
|
|
+ * Deliver a machine check interrupt to the guest.
|
|
|
|
+ * We have to do this, even if the host has handled the
|
|
|
|
+ * machine check, because machine checks use SRR0/1 and
|
|
|
|
+ * the interrupt might have trashed guest state in them.
|
|
|
|
+ */
|
|
|
|
+ kvmppc_book3s_queue_irqprio(vcpu,
|
|
|
|
+ BOOK3S_INTERRUPT_MACHINE_CHECK);
|
|
|
|
+ r = RESUME_GUEST;
|
|
|
|
+ break;
|
|
case BOOK3S_INTERRUPT_PROGRAM:
|
|
case BOOK3S_INTERRUPT_PROGRAM:
|
|
{
|
|
{
|
|
ulong flags;
|
|
ulong flags;
|
|
@@ -470,12 +597,12 @@ static int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
|
|
* have been handled already.
|
|
* have been handled already.
|
|
*/
|
|
*/
|
|
case BOOK3S_INTERRUPT_H_DATA_STORAGE:
|
|
case BOOK3S_INTERRUPT_H_DATA_STORAGE:
|
|
- r = kvmppc_book3s_hv_page_fault(run, vcpu,
|
|
|
|
- vcpu->arch.fault_dar, vcpu->arch.fault_dsisr);
|
|
|
|
|
|
+ r = RESUME_PAGE_FAULT;
|
|
break;
|
|
break;
|
|
case BOOK3S_INTERRUPT_H_INST_STORAGE:
|
|
case BOOK3S_INTERRUPT_H_INST_STORAGE:
|
|
- r = kvmppc_book3s_hv_page_fault(run, vcpu,
|
|
|
|
- kvmppc_get_pc(vcpu), 0);
|
|
|
|
|
|
+ vcpu->arch.fault_dar = kvmppc_get_pc(vcpu);
|
|
|
|
+ vcpu->arch.fault_dsisr = 0;
|
|
|
|
+ r = RESUME_PAGE_FAULT;
|
|
break;
|
|
break;
|
|
/*
|
|
/*
|
|
* This occurs if the guest executes an illegal instruction.
|
|
* This occurs if the guest executes an illegal instruction.
|
|
@@ -535,36 +662,174 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
-int kvm_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
|
|
|
|
|
|
+int kvmppc_get_one_reg(struct kvm_vcpu *vcpu, u64 id, union kvmppc_one_reg *val)
|
|
{
|
|
{
|
|
- int r = -EINVAL;
|
|
|
|
|
|
+ int r = 0;
|
|
|
|
+ long int i;
|
|
|
|
|
|
- switch (reg->id) {
|
|
|
|
|
|
+ switch (id) {
|
|
case KVM_REG_PPC_HIOR:
|
|
case KVM_REG_PPC_HIOR:
|
|
- r = put_user(0, (u64 __user *)reg->addr);
|
|
|
|
|
|
+ *val = get_reg_val(id, 0);
|
|
|
|
+ break;
|
|
|
|
+ case KVM_REG_PPC_DABR:
|
|
|
|
+ *val = get_reg_val(id, vcpu->arch.dabr);
|
|
|
|
+ break;
|
|
|
|
+ case KVM_REG_PPC_DSCR:
|
|
|
|
+ *val = get_reg_val(id, vcpu->arch.dscr);
|
|
|
|
+ break;
|
|
|
|
+ case KVM_REG_PPC_PURR:
|
|
|
|
+ *val = get_reg_val(id, vcpu->arch.purr);
|
|
|
|
+ break;
|
|
|
|
+ case KVM_REG_PPC_SPURR:
|
|
|
|
+ *val = get_reg_val(id, vcpu->arch.spurr);
|
|
|
|
+ break;
|
|
|
|
+ case KVM_REG_PPC_AMR:
|
|
|
|
+ *val = get_reg_val(id, vcpu->arch.amr);
|
|
|
|
+ break;
|
|
|
|
+ case KVM_REG_PPC_UAMOR:
|
|
|
|
+ *val = get_reg_val(id, vcpu->arch.uamor);
|
|
|
|
+ break;
|
|
|
|
+ case KVM_REG_PPC_MMCR0 ... KVM_REG_PPC_MMCRA:
|
|
|
|
+ i = id - KVM_REG_PPC_MMCR0;
|
|
|
|
+ *val = get_reg_val(id, vcpu->arch.mmcr[i]);
|
|
|
|
+ break;
|
|
|
|
+ case KVM_REG_PPC_PMC1 ... KVM_REG_PPC_PMC8:
|
|
|
|
+ i = id - KVM_REG_PPC_PMC1;
|
|
|
|
+ *val = get_reg_val(id, vcpu->arch.pmc[i]);
|
|
|
|
+ break;
|
|
|
|
+#ifdef CONFIG_VSX
|
|
|
|
+ case KVM_REG_PPC_FPR0 ... KVM_REG_PPC_FPR31:
|
|
|
|
+ if (cpu_has_feature(CPU_FTR_VSX)) {
|
|
|
|
+ /* VSX => FP reg i is stored in arch.vsr[2*i] */
|
|
|
|
+ long int i = id - KVM_REG_PPC_FPR0;
|
|
|
|
+ *val = get_reg_val(id, vcpu->arch.vsr[2 * i]);
|
|
|
|
+ } else {
|
|
|
|
+ /* let generic code handle it */
|
|
|
|
+ r = -EINVAL;
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+ case KVM_REG_PPC_VSR0 ... KVM_REG_PPC_VSR31:
|
|
|
|
+ if (cpu_has_feature(CPU_FTR_VSX)) {
|
|
|
|
+ long int i = id - KVM_REG_PPC_VSR0;
|
|
|
|
+ val->vsxval[0] = vcpu->arch.vsr[2 * i];
|
|
|
|
+ val->vsxval[1] = vcpu->arch.vsr[2 * i + 1];
|
|
|
|
+ } else {
|
|
|
|
+ r = -ENXIO;
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+#endif /* CONFIG_VSX */
|
|
|
|
+ case KVM_REG_PPC_VPA_ADDR:
|
|
|
|
+ spin_lock(&vcpu->arch.vpa_update_lock);
|
|
|
|
+ *val = get_reg_val(id, vcpu->arch.vpa.next_gpa);
|
|
|
|
+ spin_unlock(&vcpu->arch.vpa_update_lock);
|
|
|
|
+ break;
|
|
|
|
+ case KVM_REG_PPC_VPA_SLB:
|
|
|
|
+ spin_lock(&vcpu->arch.vpa_update_lock);
|
|
|
|
+ val->vpaval.addr = vcpu->arch.slb_shadow.next_gpa;
|
|
|
|
+ val->vpaval.length = vcpu->arch.slb_shadow.len;
|
|
|
|
+ spin_unlock(&vcpu->arch.vpa_update_lock);
|
|
|
|
+ break;
|
|
|
|
+ case KVM_REG_PPC_VPA_DTL:
|
|
|
|
+ spin_lock(&vcpu->arch.vpa_update_lock);
|
|
|
|
+ val->vpaval.addr = vcpu->arch.dtl.next_gpa;
|
|
|
|
+ val->vpaval.length = vcpu->arch.dtl.len;
|
|
|
|
+ spin_unlock(&vcpu->arch.vpa_update_lock);
|
|
break;
|
|
break;
|
|
default:
|
|
default:
|
|
|
|
+ r = -EINVAL;
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
return r;
|
|
return r;
|
|
}
|
|
}
|
|
|
|
|
|
-int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
|
|
|
|
|
|
+int kvmppc_set_one_reg(struct kvm_vcpu *vcpu, u64 id, union kvmppc_one_reg *val)
|
|
{
|
|
{
|
|
- int r = -EINVAL;
|
|
|
|
|
|
+ int r = 0;
|
|
|
|
+ long int i;
|
|
|
|
+ unsigned long addr, len;
|
|
|
|
|
|
- switch (reg->id) {
|
|
|
|
|
|
+ switch (id) {
|
|
case KVM_REG_PPC_HIOR:
|
|
case KVM_REG_PPC_HIOR:
|
|
- {
|
|
|
|
- u64 hior;
|
|
|
|
/* Only allow this to be set to zero */
|
|
/* Only allow this to be set to zero */
|
|
- r = get_user(hior, (u64 __user *)reg->addr);
|
|
|
|
- if (!r && (hior != 0))
|
|
|
|
|
|
+ if (set_reg_val(id, *val))
|
|
r = -EINVAL;
|
|
r = -EINVAL;
|
|
break;
|
|
break;
|
|
- }
|
|
|
|
|
|
+ case KVM_REG_PPC_DABR:
|
|
|
|
+ vcpu->arch.dabr = set_reg_val(id, *val);
|
|
|
|
+ break;
|
|
|
|
+ case KVM_REG_PPC_DSCR:
|
|
|
|
+ vcpu->arch.dscr = set_reg_val(id, *val);
|
|
|
|
+ break;
|
|
|
|
+ case KVM_REG_PPC_PURR:
|
|
|
|
+ vcpu->arch.purr = set_reg_val(id, *val);
|
|
|
|
+ break;
|
|
|
|
+ case KVM_REG_PPC_SPURR:
|
|
|
|
+ vcpu->arch.spurr = set_reg_val(id, *val);
|
|
|
|
+ break;
|
|
|
|
+ case KVM_REG_PPC_AMR:
|
|
|
|
+ vcpu->arch.amr = set_reg_val(id, *val);
|
|
|
|
+ break;
|
|
|
|
+ case KVM_REG_PPC_UAMOR:
|
|
|
|
+ vcpu->arch.uamor = set_reg_val(id, *val);
|
|
|
|
+ break;
|
|
|
|
+ case KVM_REG_PPC_MMCR0 ... KVM_REG_PPC_MMCRA:
|
|
|
|
+ i = id - KVM_REG_PPC_MMCR0;
|
|
|
|
+ vcpu->arch.mmcr[i] = set_reg_val(id, *val);
|
|
|
|
+ break;
|
|
|
|
+ case KVM_REG_PPC_PMC1 ... KVM_REG_PPC_PMC8:
|
|
|
|
+ i = id - KVM_REG_PPC_PMC1;
|
|
|
|
+ vcpu->arch.pmc[i] = set_reg_val(id, *val);
|
|
|
|
+ break;
|
|
|
|
+#ifdef CONFIG_VSX
|
|
|
|
+ case KVM_REG_PPC_FPR0 ... KVM_REG_PPC_FPR31:
|
|
|
|
+ if (cpu_has_feature(CPU_FTR_VSX)) {
|
|
|
|
+ /* VSX => FP reg i is stored in arch.vsr[2*i] */
|
|
|
|
+ long int i = id - KVM_REG_PPC_FPR0;
|
|
|
|
+ vcpu->arch.vsr[2 * i] = set_reg_val(id, *val);
|
|
|
|
+ } else {
|
|
|
|
+ /* let generic code handle it */
|
|
|
|
+ r = -EINVAL;
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+ case KVM_REG_PPC_VSR0 ... KVM_REG_PPC_VSR31:
|
|
|
|
+ if (cpu_has_feature(CPU_FTR_VSX)) {
|
|
|
|
+ long int i = id - KVM_REG_PPC_VSR0;
|
|
|
|
+ vcpu->arch.vsr[2 * i] = val->vsxval[0];
|
|
|
|
+ vcpu->arch.vsr[2 * i + 1] = val->vsxval[1];
|
|
|
|
+ } else {
|
|
|
|
+ r = -ENXIO;
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+#endif /* CONFIG_VSX */
|
|
|
|
+ case KVM_REG_PPC_VPA_ADDR:
|
|
|
|
+ addr = set_reg_val(id, *val);
|
|
|
|
+ r = -EINVAL;
|
|
|
|
+ if (!addr && (vcpu->arch.slb_shadow.next_gpa ||
|
|
|
|
+ vcpu->arch.dtl.next_gpa))
|
|
|
|
+ break;
|
|
|
|
+ r = set_vpa(vcpu, &vcpu->arch.vpa, addr, sizeof(struct lppaca));
|
|
|
|
+ break;
|
|
|
|
+ case KVM_REG_PPC_VPA_SLB:
|
|
|
|
+ addr = val->vpaval.addr;
|
|
|
|
+ len = val->vpaval.length;
|
|
|
|
+ r = -EINVAL;
|
|
|
|
+ if (addr && !vcpu->arch.vpa.next_gpa)
|
|
|
|
+ break;
|
|
|
|
+ r = set_vpa(vcpu, &vcpu->arch.slb_shadow, addr, len);
|
|
|
|
+ break;
|
|
|
|
+ case KVM_REG_PPC_VPA_DTL:
|
|
|
|
+ addr = val->vpaval.addr;
|
|
|
|
+ len = val->vpaval.length;
|
|
|
|
+ r = -EINVAL;
|
|
|
|
+ if (addr && (len < sizeof(struct dtl_entry) ||
|
|
|
|
+ !vcpu->arch.vpa.next_gpa))
|
|
|
|
+ break;
|
|
|
|
+ len -= len % sizeof(struct dtl_entry);
|
|
|
|
+ r = set_vpa(vcpu, &vcpu->arch.dtl, addr, len);
|
|
|
|
+ break;
|
|
default:
|
|
default:
|
|
|
|
+ r = -EINVAL;
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -599,20 +864,18 @@ struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id)
|
|
goto free_vcpu;
|
|
goto free_vcpu;
|
|
|
|
|
|
vcpu->arch.shared = &vcpu->arch.shregs;
|
|
vcpu->arch.shared = &vcpu->arch.shregs;
|
|
- vcpu->arch.last_cpu = -1;
|
|
|
|
vcpu->arch.mmcr[0] = MMCR0_FC;
|
|
vcpu->arch.mmcr[0] = MMCR0_FC;
|
|
vcpu->arch.ctrl = CTRL_RUNLATCH;
|
|
vcpu->arch.ctrl = CTRL_RUNLATCH;
|
|
/* default to host PVR, since we can't spoof it */
|
|
/* default to host PVR, since we can't spoof it */
|
|
vcpu->arch.pvr = mfspr(SPRN_PVR);
|
|
vcpu->arch.pvr = mfspr(SPRN_PVR);
|
|
kvmppc_set_pvr(vcpu, vcpu->arch.pvr);
|
|
kvmppc_set_pvr(vcpu, vcpu->arch.pvr);
|
|
spin_lock_init(&vcpu->arch.vpa_update_lock);
|
|
spin_lock_init(&vcpu->arch.vpa_update_lock);
|
|
|
|
+ spin_lock_init(&vcpu->arch.tbacct_lock);
|
|
|
|
+ vcpu->arch.busy_preempt = TB_NIL;
|
|
|
|
|
|
kvmppc_mmu_book3s_hv_init(vcpu);
|
|
kvmppc_mmu_book3s_hv_init(vcpu);
|
|
|
|
|
|
- /*
|
|
|
|
- * We consider the vcpu stopped until we see the first run ioctl for it.
|
|
|
|
- */
|
|
|
|
- vcpu->arch.state = KVMPPC_VCPU_STOPPED;
|
|
|
|
|
|
+ vcpu->arch.state = KVMPPC_VCPU_NOTREADY;
|
|
|
|
|
|
init_waitqueue_head(&vcpu->arch.cpu_run);
|
|
init_waitqueue_head(&vcpu->arch.cpu_run);
|
|
|
|
|
|
@@ -624,9 +887,10 @@ struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id)
|
|
INIT_LIST_HEAD(&vcore->runnable_threads);
|
|
INIT_LIST_HEAD(&vcore->runnable_threads);
|
|
spin_lock_init(&vcore->lock);
|
|
spin_lock_init(&vcore->lock);
|
|
init_waitqueue_head(&vcore->wq);
|
|
init_waitqueue_head(&vcore->wq);
|
|
- vcore->preempt_tb = mftb();
|
|
|
|
|
|
+ vcore->preempt_tb = TB_NIL;
|
|
}
|
|
}
|
|
kvm->arch.vcores[core] = vcore;
|
|
kvm->arch.vcores[core] = vcore;
|
|
|
|
+ kvm->arch.online_vcores++;
|
|
}
|
|
}
|
|
mutex_unlock(&kvm->lock);
|
|
mutex_unlock(&kvm->lock);
|
|
|
|
|
|
@@ -637,7 +901,6 @@ struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id)
|
|
++vcore->num_threads;
|
|
++vcore->num_threads;
|
|
spin_unlock(&vcore->lock);
|
|
spin_unlock(&vcore->lock);
|
|
vcpu->arch.vcore = vcore;
|
|
vcpu->arch.vcore = vcore;
|
|
- vcpu->arch.stolen_logged = vcore->stolen_tb;
|
|
|
|
|
|
|
|
vcpu->arch.cpu_type = KVM_CPU_3S_64;
|
|
vcpu->arch.cpu_type = KVM_CPU_3S_64;
|
|
kvmppc_sanity_check(vcpu);
|
|
kvmppc_sanity_check(vcpu);
|
|
@@ -697,17 +960,18 @@ extern void xics_wake_cpu(int cpu);
|
|
static void kvmppc_remove_runnable(struct kvmppc_vcore *vc,
|
|
static void kvmppc_remove_runnable(struct kvmppc_vcore *vc,
|
|
struct kvm_vcpu *vcpu)
|
|
struct kvm_vcpu *vcpu)
|
|
{
|
|
{
|
|
- struct kvm_vcpu *v;
|
|
|
|
|
|
+ u64 now;
|
|
|
|
|
|
if (vcpu->arch.state != KVMPPC_VCPU_RUNNABLE)
|
|
if (vcpu->arch.state != KVMPPC_VCPU_RUNNABLE)
|
|
return;
|
|
return;
|
|
|
|
+ spin_lock(&vcpu->arch.tbacct_lock);
|
|
|
|
+ now = mftb();
|
|
|
|
+ vcpu->arch.busy_stolen += vcore_stolen_time(vc, now) -
|
|
|
|
+ vcpu->arch.stolen_logged;
|
|
|
|
+ vcpu->arch.busy_preempt = now;
|
|
vcpu->arch.state = KVMPPC_VCPU_BUSY_IN_HOST;
|
|
vcpu->arch.state = KVMPPC_VCPU_BUSY_IN_HOST;
|
|
|
|
+ spin_unlock(&vcpu->arch.tbacct_lock);
|
|
--vc->n_runnable;
|
|
--vc->n_runnable;
|
|
- ++vc->n_busy;
|
|
|
|
- /* decrement the physical thread id of each following vcpu */
|
|
|
|
- v = vcpu;
|
|
|
|
- list_for_each_entry_continue(v, &vc->runnable_threads, arch.run_list)
|
|
|
|
- --v->arch.ptid;
|
|
|
|
list_del(&vcpu->arch.run_list);
|
|
list_del(&vcpu->arch.run_list);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -720,6 +984,7 @@ static int kvmppc_grab_hwthread(int cpu)
|
|
|
|
|
|
/* Ensure the thread won't go into the kernel if it wakes */
|
|
/* Ensure the thread won't go into the kernel if it wakes */
|
|
tpaca->kvm_hstate.hwthread_req = 1;
|
|
tpaca->kvm_hstate.hwthread_req = 1;
|
|
|
|
+ tpaca->kvm_hstate.kvm_vcpu = NULL;
|
|
|
|
|
|
/*
|
|
/*
|
|
* If the thread is already executing in the kernel (e.g. handling
|
|
* If the thread is already executing in the kernel (e.g. handling
|
|
@@ -769,7 +1034,6 @@ static void kvmppc_start_thread(struct kvm_vcpu *vcpu)
|
|
smp_wmb();
|
|
smp_wmb();
|
|
#if defined(CONFIG_PPC_ICP_NATIVE) && defined(CONFIG_SMP)
|
|
#if defined(CONFIG_PPC_ICP_NATIVE) && defined(CONFIG_SMP)
|
|
if (vcpu->arch.ptid) {
|
|
if (vcpu->arch.ptid) {
|
|
- kvmppc_grab_hwthread(cpu);
|
|
|
|
xics_wake_cpu(cpu);
|
|
xics_wake_cpu(cpu);
|
|
++vc->n_woken;
|
|
++vc->n_woken;
|
|
}
|
|
}
|
|
@@ -795,7 +1059,8 @@ static void kvmppc_wait_for_nap(struct kvmppc_vcore *vc)
|
|
|
|
|
|
/*
|
|
/*
|
|
* Check that we are on thread 0 and that any other threads in
|
|
* Check that we are on thread 0 and that any other threads in
|
|
- * this core are off-line.
|
|
|
|
|
|
+ * this core are off-line. Then grab the threads so they can't
|
|
|
|
+ * enter the kernel.
|
|
*/
|
|
*/
|
|
static int on_primary_thread(void)
|
|
static int on_primary_thread(void)
|
|
{
|
|
{
|
|
@@ -807,6 +1072,17 @@ static int on_primary_thread(void)
|
|
while (++thr < threads_per_core)
|
|
while (++thr < threads_per_core)
|
|
if (cpu_online(cpu + thr))
|
|
if (cpu_online(cpu + thr))
|
|
return 0;
|
|
return 0;
|
|
|
|
+
|
|
|
|
+ /* Grab all hw threads so they can't go into the kernel */
|
|
|
|
+ for (thr = 1; thr < threads_per_core; ++thr) {
|
|
|
|
+ if (kvmppc_grab_hwthread(cpu + thr)) {
|
|
|
|
+ /* Couldn't grab one; let the others go */
|
|
|
|
+ do {
|
|
|
|
+ kvmppc_release_hwthread(cpu + thr);
|
|
|
|
+ } while (--thr > 0);
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
return 1;
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -814,21 +1090,24 @@ static int on_primary_thread(void)
|
|
* Run a set of guest threads on a physical core.
|
|
* Run a set of guest threads on a physical core.
|
|
* Called with vc->lock held.
|
|
* Called with vc->lock held.
|
|
*/
|
|
*/
|
|
-static int kvmppc_run_core(struct kvmppc_vcore *vc)
|
|
|
|
|
|
+static void kvmppc_run_core(struct kvmppc_vcore *vc)
|
|
{
|
|
{
|
|
struct kvm_vcpu *vcpu, *vcpu0, *vnext;
|
|
struct kvm_vcpu *vcpu, *vcpu0, *vnext;
|
|
long ret;
|
|
long ret;
|
|
u64 now;
|
|
u64 now;
|
|
int ptid, i, need_vpa_update;
|
|
int ptid, i, need_vpa_update;
|
|
|
|
+ int srcu_idx;
|
|
|
|
+ struct kvm_vcpu *vcpus_to_update[threads_per_core];
|
|
|
|
|
|
/* don't start if any threads have a signal pending */
|
|
/* don't start if any threads have a signal pending */
|
|
need_vpa_update = 0;
|
|
need_vpa_update = 0;
|
|
list_for_each_entry(vcpu, &vc->runnable_threads, arch.run_list) {
|
|
list_for_each_entry(vcpu, &vc->runnable_threads, arch.run_list) {
|
|
if (signal_pending(vcpu->arch.run_task))
|
|
if (signal_pending(vcpu->arch.run_task))
|
|
- return 0;
|
|
|
|
- need_vpa_update |= vcpu->arch.vpa.update_pending |
|
|
|
|
- vcpu->arch.slb_shadow.update_pending |
|
|
|
|
- vcpu->arch.dtl.update_pending;
|
|
|
|
|
|
+ return;
|
|
|
|
+ if (vcpu->arch.vpa.update_pending ||
|
|
|
|
+ vcpu->arch.slb_shadow.update_pending ||
|
|
|
|
+ vcpu->arch.dtl.update_pending)
|
|
|
|
+ vcpus_to_update[need_vpa_update++] = vcpu;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -838,7 +1117,7 @@ static int kvmppc_run_core(struct kvmppc_vcore *vc)
|
|
vc->n_woken = 0;
|
|
vc->n_woken = 0;
|
|
vc->nap_count = 0;
|
|
vc->nap_count = 0;
|
|
vc->entry_exit_count = 0;
|
|
vc->entry_exit_count = 0;
|
|
- vc->vcore_state = VCORE_RUNNING;
|
|
|
|
|
|
+ vc->vcore_state = VCORE_STARTING;
|
|
vc->in_guest = 0;
|
|
vc->in_guest = 0;
|
|
vc->napping_threads = 0;
|
|
vc->napping_threads = 0;
|
|
|
|
|
|
@@ -848,23 +1127,11 @@ static int kvmppc_run_core(struct kvmppc_vcore *vc)
|
|
*/
|
|
*/
|
|
if (need_vpa_update) {
|
|
if (need_vpa_update) {
|
|
spin_unlock(&vc->lock);
|
|
spin_unlock(&vc->lock);
|
|
- list_for_each_entry(vcpu, &vc->runnable_threads, arch.run_list)
|
|
|
|
- kvmppc_update_vpas(vcpu);
|
|
|
|
|
|
+ for (i = 0; i < need_vpa_update; ++i)
|
|
|
|
+ kvmppc_update_vpas(vcpus_to_update[i]);
|
|
spin_lock(&vc->lock);
|
|
spin_lock(&vc->lock);
|
|
}
|
|
}
|
|
|
|
|
|
- /*
|
|
|
|
- * Make sure we are running on thread 0, and that
|
|
|
|
- * secondary threads are offline.
|
|
|
|
- * XXX we should also block attempts to bring any
|
|
|
|
- * secondary threads online.
|
|
|
|
- */
|
|
|
|
- if (threads_per_core > 1 && !on_primary_thread()) {
|
|
|
|
- list_for_each_entry(vcpu, &vc->runnable_threads, arch.run_list)
|
|
|
|
- vcpu->arch.ret = -EBUSY;
|
|
|
|
- goto out;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
/*
|
|
/*
|
|
* Assign physical thread IDs, first to non-ceded vcpus
|
|
* Assign physical thread IDs, first to non-ceded vcpus
|
|
* and then to ceded ones.
|
|
* and then to ceded ones.
|
|
@@ -879,28 +1146,36 @@ static int kvmppc_run_core(struct kvmppc_vcore *vc)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!vcpu0)
|
|
if (!vcpu0)
|
|
- return 0; /* nothing to run */
|
|
|
|
|
|
+ goto out; /* nothing to run; should never happen */
|
|
list_for_each_entry(vcpu, &vc->runnable_threads, arch.run_list)
|
|
list_for_each_entry(vcpu, &vc->runnable_threads, arch.run_list)
|
|
if (vcpu->arch.ceded)
|
|
if (vcpu->arch.ceded)
|
|
vcpu->arch.ptid = ptid++;
|
|
vcpu->arch.ptid = ptid++;
|
|
|
|
|
|
- vc->stolen_tb += mftb() - vc->preempt_tb;
|
|
|
|
|
|
+ /*
|
|
|
|
+ * Make sure we are running on thread 0, and that
|
|
|
|
+ * secondary threads are offline.
|
|
|
|
+ */
|
|
|
|
+ if (threads_per_core > 1 && !on_primary_thread()) {
|
|
|
|
+ list_for_each_entry(vcpu, &vc->runnable_threads, arch.run_list)
|
|
|
|
+ vcpu->arch.ret = -EBUSY;
|
|
|
|
+ goto out;
|
|
|
|
+ }
|
|
|
|
+
|
|
vc->pcpu = smp_processor_id();
|
|
vc->pcpu = smp_processor_id();
|
|
list_for_each_entry(vcpu, &vc->runnable_threads, arch.run_list) {
|
|
list_for_each_entry(vcpu, &vc->runnable_threads, arch.run_list) {
|
|
kvmppc_start_thread(vcpu);
|
|
kvmppc_start_thread(vcpu);
|
|
kvmppc_create_dtl_entry(vcpu, vc);
|
|
kvmppc_create_dtl_entry(vcpu, vc);
|
|
}
|
|
}
|
|
- /* Grab any remaining hw threads so they can't go into the kernel */
|
|
|
|
- for (i = ptid; i < threads_per_core; ++i)
|
|
|
|
- kvmppc_grab_hwthread(vc->pcpu + i);
|
|
|
|
|
|
|
|
|
|
+ vc->vcore_state = VCORE_RUNNING;
|
|
preempt_disable();
|
|
preempt_disable();
|
|
spin_unlock(&vc->lock);
|
|
spin_unlock(&vc->lock);
|
|
|
|
|
|
kvm_guest_enter();
|
|
kvm_guest_enter();
|
|
|
|
+
|
|
|
|
+ srcu_idx = srcu_read_lock(&vcpu0->kvm->srcu);
|
|
|
|
+
|
|
__kvmppc_vcore_entry(NULL, vcpu0);
|
|
__kvmppc_vcore_entry(NULL, vcpu0);
|
|
- for (i = 0; i < threads_per_core; ++i)
|
|
|
|
- kvmppc_release_hwthread(vc->pcpu + i);
|
|
|
|
|
|
|
|
spin_lock(&vc->lock);
|
|
spin_lock(&vc->lock);
|
|
/* disable sending of IPIs on virtual external irqs */
|
|
/* disable sending of IPIs on virtual external irqs */
|
|
@@ -909,10 +1184,14 @@ static int kvmppc_run_core(struct kvmppc_vcore *vc)
|
|
/* wait for secondary threads to finish writing their state to memory */
|
|
/* wait for secondary threads to finish writing their state to memory */
|
|
if (vc->nap_count < vc->n_woken)
|
|
if (vc->nap_count < vc->n_woken)
|
|
kvmppc_wait_for_nap(vc);
|
|
kvmppc_wait_for_nap(vc);
|
|
|
|
+ for (i = 0; i < threads_per_core; ++i)
|
|
|
|
+ kvmppc_release_hwthread(vc->pcpu + i);
|
|
/* prevent other vcpu threads from doing kvmppc_start_thread() now */
|
|
/* prevent other vcpu threads from doing kvmppc_start_thread() now */
|
|
vc->vcore_state = VCORE_EXITING;
|
|
vc->vcore_state = VCORE_EXITING;
|
|
spin_unlock(&vc->lock);
|
|
spin_unlock(&vc->lock);
|
|
|
|
|
|
|
|
+ srcu_read_unlock(&vcpu0->kvm->srcu, srcu_idx);
|
|
|
|
+
|
|
/* make sure updates to secondary vcpu structs are visible now */
|
|
/* make sure updates to secondary vcpu structs are visible now */
|
|
smp_mb();
|
|
smp_mb();
|
|
kvm_guest_exit();
|
|
kvm_guest_exit();
|
|
@@ -920,6 +1199,7 @@ static int kvmppc_run_core(struct kvmppc_vcore *vc)
|
|
preempt_enable();
|
|
preempt_enable();
|
|
kvm_resched(vcpu);
|
|
kvm_resched(vcpu);
|
|
|
|
|
|
|
|
+ spin_lock(&vc->lock);
|
|
now = get_tb();
|
|
now = get_tb();
|
|
list_for_each_entry(vcpu, &vc->runnable_threads, arch.run_list) {
|
|
list_for_each_entry(vcpu, &vc->runnable_threads, arch.run_list) {
|
|
/* cancel pending dec exception if dec is positive */
|
|
/* cancel pending dec exception if dec is positive */
|
|
@@ -943,10 +1223,8 @@ static int kvmppc_run_core(struct kvmppc_vcore *vc)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- spin_lock(&vc->lock);
|
|
|
|
out:
|
|
out:
|
|
vc->vcore_state = VCORE_INACTIVE;
|
|
vc->vcore_state = VCORE_INACTIVE;
|
|
- vc->preempt_tb = mftb();
|
|
|
|
list_for_each_entry_safe(vcpu, vnext, &vc->runnable_threads,
|
|
list_for_each_entry_safe(vcpu, vnext, &vc->runnable_threads,
|
|
arch.run_list) {
|
|
arch.run_list) {
|
|
if (vcpu->arch.ret != RESUME_GUEST) {
|
|
if (vcpu->arch.ret != RESUME_GUEST) {
|
|
@@ -954,8 +1232,6 @@ static int kvmppc_run_core(struct kvmppc_vcore *vc)
|
|
wake_up(&vcpu->arch.cpu_run);
|
|
wake_up(&vcpu->arch.cpu_run);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
-
|
|
|
|
- return 1;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -979,20 +1255,11 @@ static void kvmppc_wait_for_exec(struct kvm_vcpu *vcpu, int wait_state)
|
|
static void kvmppc_vcore_blocked(struct kvmppc_vcore *vc)
|
|
static void kvmppc_vcore_blocked(struct kvmppc_vcore *vc)
|
|
{
|
|
{
|
|
DEFINE_WAIT(wait);
|
|
DEFINE_WAIT(wait);
|
|
- struct kvm_vcpu *v;
|
|
|
|
- int all_idle = 1;
|
|
|
|
|
|
|
|
prepare_to_wait(&vc->wq, &wait, TASK_INTERRUPTIBLE);
|
|
prepare_to_wait(&vc->wq, &wait, TASK_INTERRUPTIBLE);
|
|
vc->vcore_state = VCORE_SLEEPING;
|
|
vc->vcore_state = VCORE_SLEEPING;
|
|
spin_unlock(&vc->lock);
|
|
spin_unlock(&vc->lock);
|
|
- list_for_each_entry(v, &vc->runnable_threads, arch.run_list) {
|
|
|
|
- if (!v->arch.ceded || v->arch.pending_exceptions) {
|
|
|
|
- all_idle = 0;
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- if (all_idle)
|
|
|
|
- schedule();
|
|
|
|
|
|
+ schedule();
|
|
finish_wait(&vc->wq, &wait);
|
|
finish_wait(&vc->wq, &wait);
|
|
spin_lock(&vc->lock);
|
|
spin_lock(&vc->lock);
|
|
vc->vcore_state = VCORE_INACTIVE;
|
|
vc->vcore_state = VCORE_INACTIVE;
|
|
@@ -1001,13 +1268,13 @@ static void kvmppc_vcore_blocked(struct kvmppc_vcore *vc)
|
|
static int kvmppc_run_vcpu(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
|
|
static int kvmppc_run_vcpu(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
|
|
{
|
|
{
|
|
int n_ceded;
|
|
int n_ceded;
|
|
- int prev_state;
|
|
|
|
struct kvmppc_vcore *vc;
|
|
struct kvmppc_vcore *vc;
|
|
struct kvm_vcpu *v, *vn;
|
|
struct kvm_vcpu *v, *vn;
|
|
|
|
|
|
kvm_run->exit_reason = 0;
|
|
kvm_run->exit_reason = 0;
|
|
vcpu->arch.ret = RESUME_GUEST;
|
|
vcpu->arch.ret = RESUME_GUEST;
|
|
vcpu->arch.trap = 0;
|
|
vcpu->arch.trap = 0;
|
|
|
|
+ kvmppc_update_vpas(vcpu);
|
|
|
|
|
|
/*
|
|
/*
|
|
* Synchronize with other threads in this virtual core
|
|
* Synchronize with other threads in this virtual core
|
|
@@ -1017,8 +1284,9 @@ static int kvmppc_run_vcpu(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
|
|
vcpu->arch.ceded = 0;
|
|
vcpu->arch.ceded = 0;
|
|
vcpu->arch.run_task = current;
|
|
vcpu->arch.run_task = current;
|
|
vcpu->arch.kvm_run = kvm_run;
|
|
vcpu->arch.kvm_run = kvm_run;
|
|
- prev_state = vcpu->arch.state;
|
|
|
|
|
|
+ vcpu->arch.stolen_logged = vcore_stolen_time(vc, mftb());
|
|
vcpu->arch.state = KVMPPC_VCPU_RUNNABLE;
|
|
vcpu->arch.state = KVMPPC_VCPU_RUNNABLE;
|
|
|
|
+ vcpu->arch.busy_preempt = TB_NIL;
|
|
list_add_tail(&vcpu->arch.run_list, &vc->runnable_threads);
|
|
list_add_tail(&vcpu->arch.run_list, &vc->runnable_threads);
|
|
++vc->n_runnable;
|
|
++vc->n_runnable;
|
|
|
|
|
|
@@ -1027,33 +1295,26 @@ static int kvmppc_run_vcpu(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
|
|
* If the vcore is already running, we may be able to start
|
|
* If the vcore is already running, we may be able to start
|
|
* this thread straight away and have it join in.
|
|
* this thread straight away and have it join in.
|
|
*/
|
|
*/
|
|
- if (prev_state == KVMPPC_VCPU_STOPPED) {
|
|
|
|
|
|
+ if (!signal_pending(current)) {
|
|
if (vc->vcore_state == VCORE_RUNNING &&
|
|
if (vc->vcore_state == VCORE_RUNNING &&
|
|
VCORE_EXIT_COUNT(vc) == 0) {
|
|
VCORE_EXIT_COUNT(vc) == 0) {
|
|
vcpu->arch.ptid = vc->n_runnable - 1;
|
|
vcpu->arch.ptid = vc->n_runnable - 1;
|
|
|
|
+ kvmppc_create_dtl_entry(vcpu, vc);
|
|
kvmppc_start_thread(vcpu);
|
|
kvmppc_start_thread(vcpu);
|
|
|
|
+ } else if (vc->vcore_state == VCORE_SLEEPING) {
|
|
|
|
+ wake_up(&vc->wq);
|
|
}
|
|
}
|
|
|
|
|
|
- } else if (prev_state == KVMPPC_VCPU_BUSY_IN_HOST)
|
|
|
|
- --vc->n_busy;
|
|
|
|
|
|
+ }
|
|
|
|
|
|
while (vcpu->arch.state == KVMPPC_VCPU_RUNNABLE &&
|
|
while (vcpu->arch.state == KVMPPC_VCPU_RUNNABLE &&
|
|
!signal_pending(current)) {
|
|
!signal_pending(current)) {
|
|
- if (vc->n_busy || vc->vcore_state != VCORE_INACTIVE) {
|
|
|
|
|
|
+ if (vc->vcore_state != VCORE_INACTIVE) {
|
|
spin_unlock(&vc->lock);
|
|
spin_unlock(&vc->lock);
|
|
kvmppc_wait_for_exec(vcpu, TASK_INTERRUPTIBLE);
|
|
kvmppc_wait_for_exec(vcpu, TASK_INTERRUPTIBLE);
|
|
spin_lock(&vc->lock);
|
|
spin_lock(&vc->lock);
|
|
continue;
|
|
continue;
|
|
}
|
|
}
|
|
- vc->runner = vcpu;
|
|
|
|
- n_ceded = 0;
|
|
|
|
- list_for_each_entry(v, &vc->runnable_threads, arch.run_list)
|
|
|
|
- n_ceded += v->arch.ceded;
|
|
|
|
- if (n_ceded == vc->n_runnable)
|
|
|
|
- kvmppc_vcore_blocked(vc);
|
|
|
|
- else
|
|
|
|
- kvmppc_run_core(vc);
|
|
|
|
-
|
|
|
|
list_for_each_entry_safe(v, vn, &vc->runnable_threads,
|
|
list_for_each_entry_safe(v, vn, &vc->runnable_threads,
|
|
arch.run_list) {
|
|
arch.run_list) {
|
|
kvmppc_core_prepare_to_enter(v);
|
|
kvmppc_core_prepare_to_enter(v);
|
|
@@ -1065,22 +1326,40 @@ static int kvmppc_run_vcpu(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
|
|
wake_up(&v->arch.cpu_run);
|
|
wake_up(&v->arch.cpu_run);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+ if (!vc->n_runnable || vcpu->arch.state != KVMPPC_VCPU_RUNNABLE)
|
|
|
|
+ break;
|
|
|
|
+ vc->runner = vcpu;
|
|
|
|
+ n_ceded = 0;
|
|
|
|
+ list_for_each_entry(v, &vc->runnable_threads, arch.run_list)
|
|
|
|
+ if (!v->arch.pending_exceptions)
|
|
|
|
+ n_ceded += v->arch.ceded;
|
|
|
|
+ if (n_ceded == vc->n_runnable)
|
|
|
|
+ kvmppc_vcore_blocked(vc);
|
|
|
|
+ else
|
|
|
|
+ kvmppc_run_core(vc);
|
|
vc->runner = NULL;
|
|
vc->runner = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
- if (signal_pending(current)) {
|
|
|
|
- if (vc->vcore_state == VCORE_RUNNING ||
|
|
|
|
- vc->vcore_state == VCORE_EXITING) {
|
|
|
|
- spin_unlock(&vc->lock);
|
|
|
|
- kvmppc_wait_for_exec(vcpu, TASK_UNINTERRUPTIBLE);
|
|
|
|
- spin_lock(&vc->lock);
|
|
|
|
- }
|
|
|
|
- if (vcpu->arch.state == KVMPPC_VCPU_RUNNABLE) {
|
|
|
|
- kvmppc_remove_runnable(vc, vcpu);
|
|
|
|
- vcpu->stat.signal_exits++;
|
|
|
|
- kvm_run->exit_reason = KVM_EXIT_INTR;
|
|
|
|
- vcpu->arch.ret = -EINTR;
|
|
|
|
- }
|
|
|
|
|
|
+ while (vcpu->arch.state == KVMPPC_VCPU_RUNNABLE &&
|
|
|
|
+ (vc->vcore_state == VCORE_RUNNING ||
|
|
|
|
+ vc->vcore_state == VCORE_EXITING)) {
|
|
|
|
+ spin_unlock(&vc->lock);
|
|
|
|
+ kvmppc_wait_for_exec(vcpu, TASK_UNINTERRUPTIBLE);
|
|
|
|
+ spin_lock(&vc->lock);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (vcpu->arch.state == KVMPPC_VCPU_RUNNABLE) {
|
|
|
|
+ kvmppc_remove_runnable(vc, vcpu);
|
|
|
|
+ vcpu->stat.signal_exits++;
|
|
|
|
+ kvm_run->exit_reason = KVM_EXIT_INTR;
|
|
|
|
+ vcpu->arch.ret = -EINTR;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (vc->n_runnable && vc->vcore_state == VCORE_INACTIVE) {
|
|
|
|
+ /* Wake up some vcpu to run the core */
|
|
|
|
+ v = list_first_entry(&vc->runnable_threads,
|
|
|
|
+ struct kvm_vcpu, arch.run_list);
|
|
|
|
+ wake_up(&v->arch.cpu_run);
|
|
}
|
|
}
|
|
|
|
|
|
spin_unlock(&vc->lock);
|
|
spin_unlock(&vc->lock);
|
|
@@ -1090,6 +1369,7 @@ static int kvmppc_run_vcpu(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
|
|
int kvmppc_vcpu_run(struct kvm_run *run, struct kvm_vcpu *vcpu)
|
|
int kvmppc_vcpu_run(struct kvm_run *run, struct kvm_vcpu *vcpu)
|
|
{
|
|
{
|
|
int r;
|
|
int r;
|
|
|
|
+ int srcu_idx;
|
|
|
|
|
|
if (!vcpu->arch.sane) {
|
|
if (!vcpu->arch.sane) {
|
|
run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
|
|
run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
|
|
@@ -1120,6 +1400,7 @@ int kvmppc_vcpu_run(struct kvm_run *run, struct kvm_vcpu *vcpu)
|
|
flush_vsx_to_thread(current);
|
|
flush_vsx_to_thread(current);
|
|
vcpu->arch.wqp = &vcpu->arch.vcore->wq;
|
|
vcpu->arch.wqp = &vcpu->arch.vcore->wq;
|
|
vcpu->arch.pgdir = current->mm->pgd;
|
|
vcpu->arch.pgdir = current->mm->pgd;
|
|
|
|
+ vcpu->arch.state = KVMPPC_VCPU_BUSY_IN_HOST;
|
|
|
|
|
|
do {
|
|
do {
|
|
r = kvmppc_run_vcpu(run, vcpu);
|
|
r = kvmppc_run_vcpu(run, vcpu);
|
|
@@ -1128,10 +1409,16 @@ int kvmppc_vcpu_run(struct kvm_run *run, struct kvm_vcpu *vcpu)
|
|
!(vcpu->arch.shregs.msr & MSR_PR)) {
|
|
!(vcpu->arch.shregs.msr & MSR_PR)) {
|
|
r = kvmppc_pseries_do_hcall(vcpu);
|
|
r = kvmppc_pseries_do_hcall(vcpu);
|
|
kvmppc_core_prepare_to_enter(vcpu);
|
|
kvmppc_core_prepare_to_enter(vcpu);
|
|
|
|
+ } else if (r == RESUME_PAGE_FAULT) {
|
|
|
|
+ srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
|
|
|
|
+ r = kvmppc_book3s_hv_page_fault(run, vcpu,
|
|
|
|
+ vcpu->arch.fault_dar, vcpu->arch.fault_dsisr);
|
|
|
|
+ srcu_read_unlock(&vcpu->kvm->srcu, srcu_idx);
|
|
}
|
|
}
|
|
} while (r == RESUME_GUEST);
|
|
} while (r == RESUME_GUEST);
|
|
|
|
|
|
out:
|
|
out:
|
|
|
|
+ vcpu->arch.state = KVMPPC_VCPU_NOTREADY;
|
|
atomic_dec(&vcpu->kvm->arch.vcpus_running);
|
|
atomic_dec(&vcpu->kvm->arch.vcpus_running);
|
|
return r;
|
|
return r;
|
|
}
|
|
}
|
|
@@ -1273,7 +1560,7 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log)
|
|
n = kvm_dirty_bitmap_bytes(memslot);
|
|
n = kvm_dirty_bitmap_bytes(memslot);
|
|
memset(memslot->dirty_bitmap, 0, n);
|
|
memset(memslot->dirty_bitmap, 0, n);
|
|
|
|
|
|
- r = kvmppc_hv_get_dirty_log(kvm, memslot);
|
|
|
|
|
|
+ r = kvmppc_hv_get_dirty_log(kvm, memslot, memslot->dirty_bitmap);
|
|
if (r)
|
|
if (r)
|
|
goto out;
|
|
goto out;
|
|
|
|
|
|
@@ -1287,67 +1574,88 @@ out:
|
|
return r;
|
|
return r;
|
|
}
|
|
}
|
|
|
|
|
|
-static unsigned long slb_pgsize_encoding(unsigned long psize)
|
|
|
|
|
|
+static void unpin_slot(struct kvm_memory_slot *memslot)
|
|
{
|
|
{
|
|
- unsigned long senc = 0;
|
|
|
|
|
|
+ unsigned long *physp;
|
|
|
|
+ unsigned long j, npages, pfn;
|
|
|
|
+ struct page *page;
|
|
|
|
|
|
- if (psize > 0x1000) {
|
|
|
|
- senc = SLB_VSID_L;
|
|
|
|
- if (psize == 0x10000)
|
|
|
|
- senc |= SLB_VSID_LP_01;
|
|
|
|
|
|
+ physp = memslot->arch.slot_phys;
|
|
|
|
+ npages = memslot->npages;
|
|
|
|
+ if (!physp)
|
|
|
|
+ return;
|
|
|
|
+ for (j = 0; j < npages; j++) {
|
|
|
|
+ if (!(physp[j] & KVMPPC_GOT_PAGE))
|
|
|
|
+ continue;
|
|
|
|
+ pfn = physp[j] >> PAGE_SHIFT;
|
|
|
|
+ page = pfn_to_page(pfn);
|
|
|
|
+ SetPageDirty(page);
|
|
|
|
+ put_page(page);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void kvmppc_core_free_memslot(struct kvm_memory_slot *free,
|
|
|
|
+ struct kvm_memory_slot *dont)
|
|
|
|
+{
|
|
|
|
+ if (!dont || free->arch.rmap != dont->arch.rmap) {
|
|
|
|
+ vfree(free->arch.rmap);
|
|
|
|
+ free->arch.rmap = NULL;
|
|
|
|
+ }
|
|
|
|
+ if (!dont || free->arch.slot_phys != dont->arch.slot_phys) {
|
|
|
|
+ unpin_slot(free);
|
|
|
|
+ vfree(free->arch.slot_phys);
|
|
|
|
+ free->arch.slot_phys = NULL;
|
|
}
|
|
}
|
|
- return senc;
|
|
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+int kvmppc_core_create_memslot(struct kvm_memory_slot *slot,
|
|
|
|
+ unsigned long npages)
|
|
|
|
+{
|
|
|
|
+ slot->arch.rmap = vzalloc(npages * sizeof(*slot->arch.rmap));
|
|
|
|
+ if (!slot->arch.rmap)
|
|
|
|
+ return -ENOMEM;
|
|
|
|
+ slot->arch.slot_phys = NULL;
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
|
|
|
|
int kvmppc_core_prepare_memory_region(struct kvm *kvm,
|
|
int kvmppc_core_prepare_memory_region(struct kvm *kvm,
|
|
- struct kvm_userspace_memory_region *mem)
|
|
|
|
|
|
+ struct kvm_memory_slot *memslot,
|
|
|
|
+ struct kvm_userspace_memory_region *mem)
|
|
{
|
|
{
|
|
- unsigned long npages;
|
|
|
|
unsigned long *phys;
|
|
unsigned long *phys;
|
|
|
|
|
|
- /* Allocate a slot_phys array */
|
|
|
|
- phys = kvm->arch.slot_phys[mem->slot];
|
|
|
|
- if (!kvm->arch.using_mmu_notifiers && !phys) {
|
|
|
|
- npages = mem->memory_size >> PAGE_SHIFT;
|
|
|
|
- phys = vzalloc(npages * sizeof(unsigned long));
|
|
|
|
|
|
+ /* Allocate a slot_phys array if needed */
|
|
|
|
+ phys = memslot->arch.slot_phys;
|
|
|
|
+ if (!kvm->arch.using_mmu_notifiers && !phys && memslot->npages) {
|
|
|
|
+ phys = vzalloc(memslot->npages * sizeof(unsigned long));
|
|
if (!phys)
|
|
if (!phys)
|
|
return -ENOMEM;
|
|
return -ENOMEM;
|
|
- kvm->arch.slot_phys[mem->slot] = phys;
|
|
|
|
- kvm->arch.slot_npages[mem->slot] = npages;
|
|
|
|
|
|
+ memslot->arch.slot_phys = phys;
|
|
}
|
|
}
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
-static void unpin_slot(struct kvm *kvm, int slot_id)
|
|
|
|
|
|
+void kvmppc_core_commit_memory_region(struct kvm *kvm,
|
|
|
|
+ struct kvm_userspace_memory_region *mem,
|
|
|
|
+ struct kvm_memory_slot old)
|
|
{
|
|
{
|
|
- unsigned long *physp;
|
|
|
|
- unsigned long j, npages, pfn;
|
|
|
|
- struct page *page;
|
|
|
|
|
|
+ unsigned long npages = mem->memory_size >> PAGE_SHIFT;
|
|
|
|
+ struct kvm_memory_slot *memslot;
|
|
|
|
|
|
- physp = kvm->arch.slot_phys[slot_id];
|
|
|
|
- npages = kvm->arch.slot_npages[slot_id];
|
|
|
|
- if (physp) {
|
|
|
|
- spin_lock(&kvm->arch.slot_phys_lock);
|
|
|
|
- for (j = 0; j < npages; j++) {
|
|
|
|
- if (!(physp[j] & KVMPPC_GOT_PAGE))
|
|
|
|
- continue;
|
|
|
|
- pfn = physp[j] >> PAGE_SHIFT;
|
|
|
|
- page = pfn_to_page(pfn);
|
|
|
|
- SetPageDirty(page);
|
|
|
|
- put_page(page);
|
|
|
|
- }
|
|
|
|
- kvm->arch.slot_phys[slot_id] = NULL;
|
|
|
|
- spin_unlock(&kvm->arch.slot_phys_lock);
|
|
|
|
- vfree(physp);
|
|
|
|
|
|
+ if (npages && old.npages) {
|
|
|
|
+ /*
|
|
|
|
+ * If modifying a memslot, reset all the rmap dirty bits.
|
|
|
|
+ * If this is a new memslot, we don't need to do anything
|
|
|
|
+ * since the rmap array starts out as all zeroes,
|
|
|
|
+ * i.e. no pages are dirty.
|
|
|
|
+ */
|
|
|
|
+ memslot = id_to_memslot(kvm->memslots, mem->slot);
|
|
|
|
+ kvmppc_hv_get_dirty_log(kvm, memslot, NULL);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-void kvmppc_core_commit_memory_region(struct kvm *kvm,
|
|
|
|
- struct kvm_userspace_memory_region *mem)
|
|
|
|
-{
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
static int kvmppc_hv_setup_htab_rma(struct kvm_vcpu *vcpu)
|
|
static int kvmppc_hv_setup_htab_rma(struct kvm_vcpu *vcpu)
|
|
{
|
|
{
|
|
int err = 0;
|
|
int err = 0;
|
|
@@ -1362,6 +1670,7 @@ static int kvmppc_hv_setup_htab_rma(struct kvm_vcpu *vcpu)
|
|
unsigned long rmls;
|
|
unsigned long rmls;
|
|
unsigned long *physp;
|
|
unsigned long *physp;
|
|
unsigned long i, npages;
|
|
unsigned long i, npages;
|
|
|
|
+ int srcu_idx;
|
|
|
|
|
|
mutex_lock(&kvm->lock);
|
|
mutex_lock(&kvm->lock);
|
|
if (kvm->arch.rma_setup_done)
|
|
if (kvm->arch.rma_setup_done)
|
|
@@ -1377,12 +1686,13 @@ static int kvmppc_hv_setup_htab_rma(struct kvm_vcpu *vcpu)
|
|
}
|
|
}
|
|
|
|
|
|
/* Look up the memslot for guest physical address 0 */
|
|
/* Look up the memslot for guest physical address 0 */
|
|
|
|
+ srcu_idx = srcu_read_lock(&kvm->srcu);
|
|
memslot = gfn_to_memslot(kvm, 0);
|
|
memslot = gfn_to_memslot(kvm, 0);
|
|
|
|
|
|
/* We must have some memory at 0 by now */
|
|
/* We must have some memory at 0 by now */
|
|
err = -EINVAL;
|
|
err = -EINVAL;
|
|
if (!memslot || (memslot->flags & KVM_MEMSLOT_INVALID))
|
|
if (!memslot || (memslot->flags & KVM_MEMSLOT_INVALID))
|
|
- goto out;
|
|
|
|
|
|
+ goto out_srcu;
|
|
|
|
|
|
/* Look up the VMA for the start of this memory slot */
|
|
/* Look up the VMA for the start of this memory slot */
|
|
hva = memslot->userspace_addr;
|
|
hva = memslot->userspace_addr;
|
|
@@ -1406,14 +1716,14 @@ static int kvmppc_hv_setup_htab_rma(struct kvm_vcpu *vcpu)
|
|
err = -EPERM;
|
|
err = -EPERM;
|
|
if (cpu_has_feature(CPU_FTR_ARCH_201)) {
|
|
if (cpu_has_feature(CPU_FTR_ARCH_201)) {
|
|
pr_err("KVM: CPU requires an RMO\n");
|
|
pr_err("KVM: CPU requires an RMO\n");
|
|
- goto out;
|
|
|
|
|
|
+ goto out_srcu;
|
|
}
|
|
}
|
|
|
|
|
|
/* We can handle 4k, 64k or 16M pages in the VRMA */
|
|
/* We can handle 4k, 64k or 16M pages in the VRMA */
|
|
err = -EINVAL;
|
|
err = -EINVAL;
|
|
if (!(psize == 0x1000 || psize == 0x10000 ||
|
|
if (!(psize == 0x1000 || psize == 0x10000 ||
|
|
psize == 0x1000000))
|
|
psize == 0x1000000))
|
|
- goto out;
|
|
|
|
|
|
+ goto out_srcu;
|
|
|
|
|
|
/* Update VRMASD field in the LPCR */
|
|
/* Update VRMASD field in the LPCR */
|
|
senc = slb_pgsize_encoding(psize);
|
|
senc = slb_pgsize_encoding(psize);
|
|
@@ -1436,7 +1746,7 @@ static int kvmppc_hv_setup_htab_rma(struct kvm_vcpu *vcpu)
|
|
err = -EINVAL;
|
|
err = -EINVAL;
|
|
if (rmls < 0) {
|
|
if (rmls < 0) {
|
|
pr_err("KVM: Can't use RMA of 0x%lx bytes\n", rma_size);
|
|
pr_err("KVM: Can't use RMA of 0x%lx bytes\n", rma_size);
|
|
- goto out;
|
|
|
|
|
|
+ goto out_srcu;
|
|
}
|
|
}
|
|
atomic_inc(&ri->use_count);
|
|
atomic_inc(&ri->use_count);
|
|
kvm->arch.rma = ri;
|
|
kvm->arch.rma = ri;
|
|
@@ -1465,17 +1775,24 @@ static int kvmppc_hv_setup_htab_rma(struct kvm_vcpu *vcpu)
|
|
/* Initialize phys addrs of pages in RMO */
|
|
/* Initialize phys addrs of pages in RMO */
|
|
npages = ri->npages;
|
|
npages = ri->npages;
|
|
porder = __ilog2(npages);
|
|
porder = __ilog2(npages);
|
|
- physp = kvm->arch.slot_phys[memslot->id];
|
|
|
|
- spin_lock(&kvm->arch.slot_phys_lock);
|
|
|
|
- for (i = 0; i < npages; ++i)
|
|
|
|
- physp[i] = ((ri->base_pfn + i) << PAGE_SHIFT) + porder;
|
|
|
|
- spin_unlock(&kvm->arch.slot_phys_lock);
|
|
|
|
|
|
+ physp = memslot->arch.slot_phys;
|
|
|
|
+ if (physp) {
|
|
|
|
+ if (npages > memslot->npages)
|
|
|
|
+ npages = memslot->npages;
|
|
|
|
+ spin_lock(&kvm->arch.slot_phys_lock);
|
|
|
|
+ for (i = 0; i < npages; ++i)
|
|
|
|
+ physp[i] = ((ri->base_pfn + i) << PAGE_SHIFT) +
|
|
|
|
+ porder;
|
|
|
|
+ spin_unlock(&kvm->arch.slot_phys_lock);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
/* Order updates to kvm->arch.lpcr etc. vs. rma_setup_done */
|
|
/* Order updates to kvm->arch.lpcr etc. vs. rma_setup_done */
|
|
smp_wmb();
|
|
smp_wmb();
|
|
kvm->arch.rma_setup_done = 1;
|
|
kvm->arch.rma_setup_done = 1;
|
|
err = 0;
|
|
err = 0;
|
|
|
|
+ out_srcu:
|
|
|
|
+ srcu_read_unlock(&kvm->srcu, srcu_idx);
|
|
out:
|
|
out:
|
|
mutex_unlock(&kvm->lock);
|
|
mutex_unlock(&kvm->lock);
|
|
return err;
|
|
return err;
|
|
@@ -1496,6 +1813,13 @@ int kvmppc_core_init_vm(struct kvm *kvm)
|
|
return -ENOMEM;
|
|
return -ENOMEM;
|
|
kvm->arch.lpid = lpid;
|
|
kvm->arch.lpid = lpid;
|
|
|
|
|
|
|
|
+ /*
|
|
|
|
+ * Since we don't flush the TLB when tearing down a VM,
|
|
|
|
+ * and this lpid might have previously been used,
|
|
|
|
+ * make sure we flush on each core before running the new VM.
|
|
|
|
+ */
|
|
|
|
+ cpumask_setall(&kvm->arch.need_tlb_flush);
|
|
|
|
+
|
|
INIT_LIST_HEAD(&kvm->arch.spapr_tce_tables);
|
|
INIT_LIST_HEAD(&kvm->arch.spapr_tce_tables);
|
|
|
|
|
|
kvm->arch.rma = NULL;
|
|
kvm->arch.rma = NULL;
|
|
@@ -1523,16 +1847,19 @@ int kvmppc_core_init_vm(struct kvm *kvm)
|
|
|
|
|
|
kvm->arch.using_mmu_notifiers = !!cpu_has_feature(CPU_FTR_ARCH_206);
|
|
kvm->arch.using_mmu_notifiers = !!cpu_has_feature(CPU_FTR_ARCH_206);
|
|
spin_lock_init(&kvm->arch.slot_phys_lock);
|
|
spin_lock_init(&kvm->arch.slot_phys_lock);
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Don't allow secondary CPU threads to come online
|
|
|
|
+ * while any KVM VMs exist.
|
|
|
|
+ */
|
|
|
|
+ inhibit_secondary_onlining();
|
|
|
|
+
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
void kvmppc_core_destroy_vm(struct kvm *kvm)
|
|
void kvmppc_core_destroy_vm(struct kvm *kvm)
|
|
{
|
|
{
|
|
- unsigned long i;
|
|
|
|
-
|
|
|
|
- if (!kvm->arch.using_mmu_notifiers)
|
|
|
|
- for (i = 0; i < KVM_MEM_SLOTS_NUM; i++)
|
|
|
|
- unpin_slot(kvm, i);
|
|
|
|
|
|
+ uninhibit_secondary_onlining();
|
|
|
|
|
|
if (kvm->arch.rma) {
|
|
if (kvm->arch.rma) {
|
|
kvm_release_rma(kvm->arch.rma);
|
|
kvm_release_rma(kvm->arch.rma);
|