[PATCH] KVM: PPC: Book3S HV: Fix kvm_alloc_linear in case where no linears exist

2012-02-03 Thread Paul Mackerras
In kvm_alloc_linear we were using and deferencing ri after the
list_for_each_entry had come to the end of the list.  In that
situation, ri is not really defined and probably points to the
list head.  This will happen every time if the free_linears list
is empty, for instance.  This led to a NULL pointer dereference
crash in memset on POWER7 while trying to allocate an HPT in the
case where no HPTs were preallocated.

This fixes it by using a separate variable for the return value
from the loop iterator.

Signed-off-by: Paul Mackerras pau...@samba.org
---
 arch/powerpc/kvm/book3s_hv_builtin.c |9 +
 1 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/arch/powerpc/kvm/book3s_hv_builtin.c 
b/arch/powerpc/kvm/book3s_hv_builtin.c
index bed1279..e1b60f5 100644
--- a/arch/powerpc/kvm/book3s_hv_builtin.c
+++ b/arch/powerpc/kvm/book3s_hv_builtin.c
@@ -173,9 +173,9 @@ static void __init kvm_linear_init_one(ulong size, int 
count, int type)
 
 static struct kvmppc_linear_info *kvm_alloc_linear(int type)
 {
-   struct kvmppc_linear_info *ri;
+   struct kvmppc_linear_info *ri, *ret;
 
-   ri = NULL;
+   ret = NULL;
spin_lock(linear_lock);
list_for_each_entry(ri, free_linears, list) {
if (ri-type != type)
@@ -183,11 +183,12 @@ static struct kvmppc_linear_info *kvm_alloc_linear(int 
type)
 
list_del(ri-list);
atomic_inc(ri-use_count);
+   memset(ri-base_virt, 0, ri-npages  PAGE_SHIFT);
+   ret = ri;
break;
}
spin_unlock(linear_lock);
-   memset(ri-base_virt, 0, ri-npages  PAGE_SHIFT);
-   return ri;
+   return ret;
 }
 
 static void kvm_release_linear(struct kvmppc_linear_info *ri)
-- 
1.7.8.3

--
To unsubscribe from this list: send the line unsubscribe kvm-ppc in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 1/4] KVM: PPC: Book3S HV: Save and restore CR in __kvmppc_vcore_entry

2012-02-03 Thread Paul Mackerras
The ABI specifies that CR fields CR2--CR4 are nonvolatile across function
calls.  Currently __kvmppc_vcore_entry doesn't save and restore the CR,
leading to CR2--CR4 getting corrupted with guest values, possibly leading
to incorrect behaviour in its caller.  This adds instructions to save
and restore CR at the points where we save and restore the nonvolatile
GPRs.

Signed-off-by: Paul Mackerras pau...@samba.org
---
 arch/powerpc/kvm/book3s_hv_interrupts.S |8 ++--
 1 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/arch/powerpc/kvm/book3s_hv_interrupts.S 
b/arch/powerpc/kvm/book3s_hv_interrupts.S
index 3f7b674..d3fb4df 100644
--- a/arch/powerpc/kvm/book3s_hv_interrupts.S
+++ b/arch/powerpc/kvm/book3s_hv_interrupts.S
@@ -46,8 +46,10 @@ _GLOBAL(__kvmppc_vcore_entry)
/* Save host state to the stack */
stdur1, -SWITCH_FRAME_SIZE(r1)
 
-   /* Save non-volatile registers (r14 - r31) */
+   /* Save non-volatile registers (r14 - r31) and CR */
SAVE_NVGPRS(r1)
+   mfcrr3
+   std r3, _CCR(r1)
 
/* Save host DSCR */
 BEGIN_FTR_SECTION
@@ -157,8 +159,10 @@ kvmppc_handler_highmem:
 * R13  = PACA
 */
 
-   /* Restore non-volatile host registers (r14 - r31) */
+   /* Restore non-volatile host registers (r14 - r31) and CR */
REST_NVGPRS(r1)
+   ld  r4, _CCR(r1)
+   mtcrr4
 
addir1, r1, SWITCH_FRAME_SIZE
ld  r0, PPC_LR_STKOFF(r1)
-- 
1.7.8.3

--
To unsubscribe from this list: send the line unsubscribe kvm-ppc in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 2/4] KVM: PPC: Book3S HV: Make secondary threads more robust against stray IPIs

2012-02-03 Thread Paul Mackerras
Currently on POWER7, if we are running the guest on a core and we don't
need all the hardware threads, we do nothing to ensure that the unused
threads aren't executing in the kernel (other than checking that they
are offline).  We just assume they're napping and we don't do anything
to stop them trying to enter the kernel while the guest is running.
This means that a stray IPI can wake up the hardware thread and it will
then try to enter the kernel, but since the core is in guest context,
it will execute code from the guest in hypervisor mode once it turns the
MMU on, which tends to lead to crashes or hangs in the host.

This fixes the problem by adding two new one-byte flags in the
kvmppc_host_state structure in the PACA which are used to interlock
between the primary thread and the unused secondary threads when entering
the guest.  With these flags, the primary thread can ensure that the
unused secondaries are not already in kernel mode (i.e. handling a stray
IPI) and then indicate that they should not try to enter the kernel
if they do get woken for any reason.  Instead they will go into KVM code,
find that there is no vcpu to run, acknowledge and clear the IPI and go
back to nap mode.

Signed-off-by: Paul Mackerras pau...@samba.org
---
 arch/powerpc/include/asm/kvm_book3s_asm.h |8 +++
 arch/powerpc/kernel/asm-offsets.c |2 +
 arch/powerpc/kernel/exceptions-64s.S  |   12 ++--
 arch/powerpc/kernel/idle_power7.S |7 ++
 arch/powerpc/kvm/book3s_hv.c  |   49 ++-
 arch/powerpc/kvm/book3s_hv_rmhandlers.S   |   92 +
 6 files changed, 124 insertions(+), 46 deletions(-)

diff --git a/arch/powerpc/include/asm/kvm_book3s_asm.h 
b/arch/powerpc/include/asm/kvm_book3s_asm.h
index 1f2f5b6..88609b2 100644
--- a/arch/powerpc/include/asm/kvm_book3s_asm.h
+++ b/arch/powerpc/include/asm/kvm_book3s_asm.h
@@ -79,6 +79,9 @@ struct kvmppc_host_state {
u8 napping;
 
 #ifdef CONFIG_KVM_BOOK3S_64_HV
+   u8 hwthread_req;
+   u8 hwthread_state;
+
struct kvm_vcpu *kvm_vcpu;
struct kvmppc_vcore *kvm_vcore;
unsigned long xics_phys;
@@ -122,4 +125,9 @@ struct kvmppc_book3s_shadow_vcpu {
 
 #endif /*__ASSEMBLY__ */
 
+/* Values for kvm_state */
+#define KVM_HWTHREAD_IN_KERNEL 0
+#define KVM_HWTHREAD_IN_NAP1
+#define KVM_HWTHREAD_IN_KVM2
+
 #endif /* __ASM_KVM_BOOK3S_ASM_H__ */
diff --git a/arch/powerpc/kernel/asm-offsets.c 
b/arch/powerpc/kernel/asm-offsets.c
index 8e0db0b..1914818 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -549,6 +549,8 @@ int main(void)
HSTATE_FIELD(HSTATE_IN_GUEST, in_guest);
HSTATE_FIELD(HSTATE_RESTORE_HID5, restore_hid5);
HSTATE_FIELD(HSTATE_NAPPING, napping);
+   HSTATE_FIELD(HSTATE_HWTHREAD_REQ, hwthread_req);
+   HSTATE_FIELD(HSTATE_HWTHREAD_STATE, hwthread_state);
 
 #ifdef CONFIG_KVM_BOOK3S_64_HV
HSTATE_FIELD(HSTATE_KVM_VCPU, kvm_vcpu);
diff --git a/arch/powerpc/kernel/exceptions-64s.S 
b/arch/powerpc/kernel/exceptions-64s.S
index ca9b733..1726a48 100644
--- a/arch/powerpc/kernel/exceptions-64s.S
+++ b/arch/powerpc/kernel/exceptions-64s.S
@@ -62,11 +62,13 @@ BEGIN_FTR_SECTION
GET_PACA(r13)
 
 #ifdef CONFIG_KVM_BOOK3S_64_HV
-   lbz r0,PACAPROCSTART(r13)
-   cmpwi   r0,0x80
-   bne 1f
-   li  r0,1
-   stb r0,PACAPROCSTART(r13)
+   li  r0,KVM_HWTHREAD_IN_KERNEL
+   stb r0,HSTATE_HWTHREAD_STATE(r13)
+   /* Order setting hwthread_state vs. testing hwthread_req */
+   sync
+   lbz r0,HSTATE_HWTHREAD_REQ(r13)
+   cmpwi   r0,0
+   beq 1f
b   kvm_start_guest
 1:
 #endif
diff --git a/arch/powerpc/kernel/idle_power7.S 
b/arch/powerpc/kernel/idle_power7.S
index fcdff19..95eb8c5 100644
--- a/arch/powerpc/kernel/idle_power7.S
+++ b/arch/powerpc/kernel/idle_power7.S
@@ -15,6 +15,7 @@
 #include asm/ppc_asm.h
 #include asm/asm-offsets.h
 #include asm/ppc-opcode.h
+#include asm/kvm_book3s_asm.h
 
 #undef DEBUG
 
@@ -64,6 +65,12 @@ _GLOBAL(power7_idle)
std r9,_MSR(r1)
std r1,PACAR1(r13)
 
+#ifdef CONFIG_KVM_BOOK3S_64_HV
+   /* Tell KVM we're napping */
+   li  r4,KVM_HWTHREAD_IN_NAP
+   stb r4,HSTATE_HWTHREAD_STATE(r13)
+#endif
+
/* Magic NAP mode enter sequence */
std r0,0(r1)
ptesync
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index ce1cac7..966e54c 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -569,6 +569,45 @@ static void kvmppc_remove_runnable(struct kvmppc_vcore *vc,
list_del(vcpu-arch.run_list);
 }
 
+static int kvmppc_grab_hwthread(int cpu)
+{
+   struct paca_struct *tpaca;
+   long timeout = 1000;
+
+   tpaca = paca[cpu];
+
+   /* Ensure the thread won't go into the kernel if it wakes */
+   tpaca-kvm_hstate.hwthread_req = 1;
+
+   /*
+

[PATCH 3/4] KVM: PPC: Book3S HV: Make virtual processor area registration more robust

2012-02-03 Thread Paul Mackerras
The PAPR API allows three sorts of per-virtual-processor areas to be
registered (VPA, SLB shadow buffer, and dispatch trace log), and
furthermore, these can be registered and unregistered for another
virtual CPU.  Currently we just update the vcpu fields pointing to
these areas at the time of registration or unregistration.  If this
is done on another vcpu, there is the possibility that the target vcpu
is using those fields at the time and could end up using a bogus
pointer and corrupting memory.

This fixes the race by making the target cpu itself do the update, so
we can be sure that the update happens at a time when the fields
aren't being used.  Each area now has a struct kvmppc_vpa which is
used to manage these updates.  There is also a spinlock which protects
access to all of the kvmppc_vpa structs, other than to the pinned_addr
fields.  (We could have just taken the spinlock when using the vpa,
slb_shadow or dtl fields, but that would mean taking the spinlock on
every guest entry and exit.)

This also changes 'struct dtl' (which was undefined) to 'struct dtl_entry',
which is what the rest of the kernel uses.

Signed-off-by: Paul Mackerras pau...@samba.org
---
 arch/powerpc/include/asm/hvcall.h   |   10 ++
 arch/powerpc/include/asm/kvm_host.h |   27 -
 arch/powerpc/kernel/asm-offsets.c   |2 +-
 arch/powerpc/kvm/book3s_hv.c|  226 ---
 4 files changed, 189 insertions(+), 76 deletions(-)

diff --git a/arch/powerpc/include/asm/hvcall.h 
b/arch/powerpc/include/asm/hvcall.h
index 1c324ff..318bac9 100644
--- a/arch/powerpc/include/asm/hvcall.h
+++ b/arch/powerpc/include/asm/hvcall.h
@@ -114,6 +114,16 @@
 #define H_PP1  (1UL(63-62))
 #define H_PP2  (1UL(63-63))
 
+/* Flags for H_REGISTER_VPA subfunction field */
+#define H_VPA_FUNC_SHIFT   (63-18) /* Bit posn of subfunction code */
+#define H_VPA_FUNC_MASK7UL
+#define H_VPA_REG_VPA  1UL /* Register Virtual Processor Area */
+#define H_VPA_REG_DTL  2UL /* Register Dispatch Trace Log */
+#define H_VPA_REG_SLB  3UL /* Register SLB shadow buffer */
+#define H_VPA_DEREG_VPA5UL /* Deregister Virtual Processor 
Area */
+#define H_VPA_DEREG_DTL6UL /* Deregister Dispatch Trace 
Log */
+#define H_VPA_DEREG_SLB7UL /* Deregister SLB shadow buffer 
*/
+
 /* VASI States */
 #define H_VASI_INVALID  0
 #define H_VASI_ENABLED  1
diff --git a/arch/powerpc/include/asm/kvm_host.h 
b/arch/powerpc/include/asm/kvm_host.h
index 1843d5d..0ab60ac 100644
--- a/arch/powerpc/include/asm/kvm_host.h
+++ b/arch/powerpc/include/asm/kvm_host.h
@@ -82,7 +82,7 @@ struct kvm_vcpu;
 
 struct lppaca;
 struct slb_shadow;
-struct dtl;
+struct dtl_entry;
 
 struct kvm_vm_stat {
u32 remote_tlb_flush;
@@ -271,6 +271,19 @@ struct kvmppc_vcore {
 #define VCORE_EXITING  2
 #define VCORE_SLEEPING 3
 
+/*
+ * Struct used to manage memory for a virtual processor area
+ * registered by a PAPR guest.  There are three types of area
+ * that a guest can register.
+ */
+struct kvmppc_vpa {
+   void *pinned_addr;  /* Address in kernel linear mapping */
+   void *pinned_end;   /* End of region */
+   unsigned long next_gpa; /* Guest phys addr for update */
+   unsigned long len;  /* Number of bytes required */
+   u8 update_pending;  /* 1 = update pinned_addr from next_gpa */
+};
+
 struct kvmppc_pte {
ulong eaddr;
u64 vpage;
@@ -450,11 +463,6 @@ struct kvm_vcpu_arch {
u8 prodded;
u32 last_inst;
 
-   struct lppaca *vpa;
-   struct slb_shadow *slb_shadow;
-   struct dtl *dtl;
-   struct dtl *dtl_end;
-
wait_queue_head_t *wqp;
struct kvmppc_vcore *vcore;
int ret;
@@ -479,6 +487,13 @@ struct kvm_vcpu_arch {
struct task_struct *run_task;
struct kvm_run *kvm_run;
pgd_t *pgdir;
+
+   spinlock_t vpa_update_lock;
+   struct kvmppc_vpa vpa;
+   struct kvmppc_vpa dtl;
+   struct dtl_entry *dtl_ptr;
+   unsigned long dtl_index;
+   struct kvmppc_vpa slb_shadow;
 #endif
 };
 
diff --git a/arch/powerpc/kernel/asm-offsets.c 
b/arch/powerpc/kernel/asm-offsets.c
index 1914818..f8d9e16 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -475,7 +475,7 @@ int main(void)
DEFINE(VCPU_PENDING_EXC, offsetof(struct kvm_vcpu, 
arch.pending_exceptions));
DEFINE(VCPU_CEDED, offsetof(struct kvm_vcpu, arch.ceded));
DEFINE(VCPU_PRODDED, offsetof(struct kvm_vcpu, arch.prodded));
-   DEFINE(VCPU_VPA, offsetof(struct kvm_vcpu, arch.vpa));
+   DEFINE(VCPU_VPA, offsetof(struct kvm_vcpu, arch.vpa.pinned_addr));
DEFINE(VCPU_MMCR, offsetof(struct kvm_vcpu, arch.mmcr));
DEFINE(VCPU_PMC, offsetof(struct kvm_vcpu, arch.pmc));
DEFINE(VCPU_SLB, offsetof(struct kvm_vcpu, arch.slb));
diff --git