powerpc: Provide a way for KVM to indicate that NV GPR values are lost
authorPaul Mackerras <paulus@samba.org>
Mon, 5 Dec 2011 19:47:26 +0000 (19:47 +0000)
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>
Thu, 8 Dec 2011 03:22:53 +0000 (14:22 +1100)
This fixes a problem where a CPU thread coming out of nap mode can
think it has valid values in the nonvolatile GPRs (r14 - r31) as saved
away in power7_idle, but in fact the values have been trashed because
the thread was used for KVM in the mean time.  The result is that the
thread crashes because code that called power7_idle (e.g.,
pnv_smp_cpu_kill_self()) goes to use values in registers that have
been trashed.

The bit field in SRR1 that tells whether state was lost only reflects
the most recent nap, which may not have been the nap instruction in
power7_idle.  So we need an extra PACA field to indicate that state
has been lost even if SRR1 indicates that the most recent nap didn't
lose state.  We clear this field when saving the state in power7_idle,
we set it to a non-zero value when we use the thread for KVM, and we
test it in power7_wakeup_noloss.

Signed-off-by: Paul Mackerras <paulus@samba.org>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
arch/powerpc/include/asm/paca.h
arch/powerpc/kernel/asm-offsets.c
arch/powerpc/kernel/idle_power7.S
arch/powerpc/kvm/book3s_hv_rmhandlers.S

index 17722c73ba2e91e24b31c0d5c4435d9d57b0f1c2..269c05a36d917529bc340f61cb0824e1276cd19b 100644 (file)
@@ -135,6 +135,7 @@ struct paca_struct {
        u8 hard_enabled;                /* set if irqs are enabled in MSR */
        u8 io_sync;                     /* writel() needs spin_unlock sync */
        u8 irq_work_pending;            /* IRQ_WORK interrupt while soft-disable */
+       u8 nap_state_lost;              /* NV GPR values lost in power7_idle */
 
 #ifdef CONFIG_PPC_POWERNV
        /* Pointer to OPAL machine check event structure set by the
index 7c5324f1ec9c35671fcda0fd0dffc791b25ceaa7..04caee7d9bc185a223841b4827da5576359f5be1 100644 (file)
@@ -208,6 +208,7 @@ int main(void)
        DEFINE(PACA_USER_TIME, offsetof(struct paca_struct, user_time));
        DEFINE(PACA_SYSTEM_TIME, offsetof(struct paca_struct, system_time));
        DEFINE(PACA_TRAP_SAVE, offsetof(struct paca_struct, trap_save));
+       DEFINE(PACA_NAPSTATELOST, offsetof(struct paca_struct, nap_state_lost));
 #endif /* CONFIG_PPC64 */
 
        /* RTAS */
index 3a70845a51c7be063dc90c77b194f95a69afd4f6..fcdff198da4ba9f43fe0f58a84d2bd632136ff24 100644 (file)
@@ -54,6 +54,7 @@ _GLOBAL(power7_idle)
        li      r0,0
        stb     r0,PACASOFTIRQEN(r13)   /* we'll hard-enable shortly */
        stb     r0,PACAHARDIRQEN(r13)
+       stb     r0,PACA_NAPSTATELOST(r13)
 
        /* Continue saving state */
        SAVE_GPR(2, r1)
@@ -86,6 +87,9 @@ _GLOBAL(power7_wakeup_loss)
        rfid
 
 _GLOBAL(power7_wakeup_noloss)
+       lbz     r0,PACA_NAPSTATELOST(r13)
+       cmpwi   r0,0
+       bne     .power7_wakeup_loss
        ld      r1,PACAR1(r13)
        ld      r4,_MSR(r1)
        ld      r5,_NIP(r1)
index 44d8829334ab2d9c1ec22606336177d36f41b3d5..5c8b26183f5035a9765443cf440e0b9f46df51f1 100644 (file)
@@ -112,6 +112,9 @@ kvm_start_guest:
        stbcix  r0, r5, r6              /* clear it */
        stwcix  r8, r5, r7              /* EOI it */
 
+       /* NV GPR values from power7_idle() will no longer be valid */
+       stb     r0, PACA_NAPSTATELOST(r13)
+
 .global kvmppc_hv_entry
 kvmppc_hv_entry: