KVM: PPC: Book3S HV P9: Avoid changing MSR[RI] in entry and exit
kvm_hstate.in_guest provides the equivalent of MSR[RI]=0 protection, and it covers the existing MSR[RI]=0 section in late entry and early exit, so clearing and setting MSR[RI] in those cases does not actually do anything useful. Remove the RI manipulation and replace it with comments. Make the in_guest memory accesses a bit closer to a proper critical section pattern. This speeds up guest entry/exit performance. This also removes the MSR[RI] warnings which aren't very interesting and would cause crashes if they hit due to causing an interrupt in non-recoverable code. Signed-off-by: Nicholas Piggin <npiggin@gmail.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Link: https://lore.kernel.org/r/20211123095231.1036501-48-npiggin@gmail.com
This commit is contained in:
Родитель
241d1f19f0
Коммит
f08cbf5c7d
|
@ -904,7 +904,15 @@ int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpc
|
|||
* But TM could be split out if this would be a significant benefit.
|
||||
*/
|
||||
|
||||
local_paca->kvm_hstate.in_guest = KVM_GUEST_MODE_HV_P9;
|
||||
/*
|
||||
* MSR[RI] does not need to be cleared (and is not, for radix guests
|
||||
* with no prefetch bug), because in_guest is set. If we take a SRESET
|
||||
* or MCE with in_guest set but still in HV mode, then
|
||||
* kvmppc_p9_bad_interrupt handles the interrupt, which effectively
|
||||
* clears MSR[RI] and doesn't return.
|
||||
*/
|
||||
WRITE_ONCE(local_paca->kvm_hstate.in_guest, KVM_GUEST_MODE_HV_P9);
|
||||
barrier(); /* Open in_guest critical section */
|
||||
|
||||
/*
|
||||
* Hash host, hash guest, or radix guest with prefetch bug, all have
|
||||
|
@ -916,14 +924,10 @@ int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpc
|
|||
|
||||
save_clear_host_mmu(kvm);
|
||||
|
||||
if (kvm_is_radix(kvm)) {
|
||||
if (kvm_is_radix(kvm))
|
||||
switch_mmu_to_guest_radix(kvm, vcpu, lpcr);
|
||||
if (!cpu_has_feature(CPU_FTR_P9_RADIX_PREFETCH_BUG))
|
||||
__mtmsrd(0, 1); /* clear RI */
|
||||
|
||||
} else {
|
||||
else
|
||||
switch_mmu_to_guest_hpt(kvm, vcpu, lpcr);
|
||||
}
|
||||
|
||||
/* TLBIEL uses LPID=LPIDR, so run this after setting guest LPID */
|
||||
check_need_tlb_flush(kvm, vc->pcpu, nested);
|
||||
|
@ -978,19 +982,16 @@ tm_return_to_guest:
|
|||
vcpu->arch.regs.gpr[3] = local_paca->kvm_hstate.scratch2;
|
||||
|
||||
/*
|
||||
* Only set RI after reading machine check regs (DAR, DSISR, SRR0/1)
|
||||
* and hstate scratch (which we need to move into exsave to make
|
||||
* re-entrant vs SRESET/MCE)
|
||||
* After reading machine check regs (DAR, DSISR, SRR0/1) and hstate
|
||||
* scratch (which we need to move into exsave to make re-entrant vs
|
||||
* SRESET/MCE), register state is protected from reentrancy. However
|
||||
* timebase, MMU, among other state is still set to guest, so don't
|
||||
* enable MSR[RI] here. It gets enabled at the end, after in_guest
|
||||
* is cleared.
|
||||
*
|
||||
* It is possible an NMI could come in here, which is why it is
|
||||
* important to save the above state early so it can be debugged.
|
||||
*/
|
||||
if (ri_set) {
|
||||
if (unlikely(!(mfmsr() & MSR_RI))) {
|
||||
__mtmsrd(MSR_RI, 1);
|
||||
WARN_ON_ONCE(1);
|
||||
}
|
||||
} else {
|
||||
WARN_ON_ONCE(mfmsr() & MSR_RI);
|
||||
__mtmsrd(MSR_RI, 1);
|
||||
}
|
||||
|
||||
vcpu->arch.regs.gpr[9] = exsave[EX_R9/sizeof(u64)];
|
||||
vcpu->arch.regs.gpr[10] = exsave[EX_R10/sizeof(u64)];
|
||||
|
@ -1048,13 +1049,6 @@ tm_return_to_guest:
|
|||
*/
|
||||
mtspr(SPRN_HSRR0, vcpu->arch.regs.nip);
|
||||
mtspr(SPRN_HSRR1, vcpu->arch.shregs.msr);
|
||||
|
||||
/*
|
||||
* tm_return_to_guest re-loads SRR0/1, DAR,
|
||||
* DSISR after RI is cleared, in case they had
|
||||
* been clobbered by a MCE.
|
||||
*/
|
||||
__mtmsrd(0, 1); /* clear RI */
|
||||
goto tm_return_to_guest;
|
||||
}
|
||||
}
|
||||
|
@ -1154,7 +1148,9 @@ tm_return_to_guest:
|
|||
|
||||
restore_p9_host_os_sprs(vcpu, &host_os_sprs);
|
||||
|
||||
local_paca->kvm_hstate.in_guest = KVM_GUEST_MODE_NONE;
|
||||
barrier(); /* Close in_guest critical section */
|
||||
WRITE_ONCE(local_paca->kvm_hstate.in_guest, KVM_GUEST_MODE_NONE);
|
||||
/* Interrupts are recoverable at this point */
|
||||
|
||||
/*
|
||||
* cp_abort is required if the processor supports local copy-paste
|
||||
|
|
Загрузка…
Ссылка в новой задаче