Commit 2fde6d20 authored by Paul Mackerras's avatar Paul Mackerras Committed by Benjamin Herrenschmidt

powerpc: Provide a way for KVM to indicate that NV GPR values are lost

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: default avatarPaul Mackerras <paulus@samba.org>
Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
parent cba313da
...@@ -135,6 +135,7 @@ struct paca_struct { ...@@ -135,6 +135,7 @@ struct paca_struct {
u8 hard_enabled; /* set if irqs are enabled in MSR */ u8 hard_enabled; /* set if irqs are enabled in MSR */
u8 io_sync; /* writel() needs spin_unlock sync */ u8 io_sync; /* writel() needs spin_unlock sync */
u8 irq_work_pending; /* IRQ_WORK interrupt while soft-disable */ 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 #ifdef CONFIG_PPC_POWERNV
/* Pointer to OPAL machine check event structure set by the /* Pointer to OPAL machine check event structure set by the
......
...@@ -208,6 +208,7 @@ int main(void) ...@@ -208,6 +208,7 @@ int main(void)
DEFINE(PACA_USER_TIME, offsetof(struct paca_struct, user_time)); DEFINE(PACA_USER_TIME, offsetof(struct paca_struct, user_time));
DEFINE(PACA_SYSTEM_TIME, offsetof(struct paca_struct, system_time)); DEFINE(PACA_SYSTEM_TIME, offsetof(struct paca_struct, system_time));
DEFINE(PACA_TRAP_SAVE, offsetof(struct paca_struct, trap_save)); DEFINE(PACA_TRAP_SAVE, offsetof(struct paca_struct, trap_save));
DEFINE(PACA_NAPSTATELOST, offsetof(struct paca_struct, nap_state_lost));
#endif /* CONFIG_PPC64 */ #endif /* CONFIG_PPC64 */
/* RTAS */ /* RTAS */
......
...@@ -54,6 +54,7 @@ _GLOBAL(power7_idle) ...@@ -54,6 +54,7 @@ _GLOBAL(power7_idle)
li r0,0 li r0,0
stb r0,PACASOFTIRQEN(r13) /* we'll hard-enable shortly */ stb r0,PACASOFTIRQEN(r13) /* we'll hard-enable shortly */
stb r0,PACAHARDIRQEN(r13) stb r0,PACAHARDIRQEN(r13)
stb r0,PACA_NAPSTATELOST(r13)
/* Continue saving state */ /* Continue saving state */
SAVE_GPR(2, r1) SAVE_GPR(2, r1)
...@@ -86,6 +87,9 @@ _GLOBAL(power7_wakeup_loss) ...@@ -86,6 +87,9 @@ _GLOBAL(power7_wakeup_loss)
rfid rfid
_GLOBAL(power7_wakeup_noloss) _GLOBAL(power7_wakeup_noloss)
lbz r0,PACA_NAPSTATELOST(r13)
cmpwi r0,0
bne .power7_wakeup_loss
ld r1,PACAR1(r13) ld r1,PACAR1(r13)
ld r4,_MSR(r1) ld r4,_MSR(r1)
ld r5,_NIP(r1) ld r5,_NIP(r1)
......
...@@ -112,6 +112,9 @@ kvm_start_guest: ...@@ -112,6 +112,9 @@ kvm_start_guest:
stbcix r0, r5, r6 /* clear it */ stbcix r0, r5, r6 /* clear it */
stwcix r8, r5, r7 /* EOI 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 .global kvmppc_hv_entry
kvmppc_hv_entry: kvmppc_hv_entry:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment