/* Return the trap number on this thread as the return value */
mr r3, r12
/* RFI into the highmem handler */
mfmsr r6
li r0, MSR_RI
andc r6, r6, r0
mtmsrd r6, 1/* Clear RI in MSR */
mtsrr0 r8
mtsrr1 r7
RFI_TO_KERNEL
kvmppc_primary_no_guest: /* We handle this much like a ceded vcpu */ /* put the HDEC into the DEC, since HDEC interrupts don't wake us */ /* HDEC may be larger than DEC for arch >= v3.00, but since the */ /* HDEC value came from DEC in the first place, it will fit */
mfspr r3, SPRN_HDEC
mtspr SPRN_DEC, r3 /* *MakesuretheprimaryhasfinishedtheMMUswitch. *Weshouldnevergethereonasecondarythread,but *checkitforrobustness'sake.
*/ ld r5, HSTATE_KVM_VCORE(r13) 65: lbz r0, VCORE_IN_GUEST(r5)
cmpwi r0, 0
beq 65b /* Set LPCR. */ ld r8,VCORE_LPCR(r5)
mtspr SPRN_LPCR,r8
isync /* set our bit in napping_threads */ ld r5, HSTATE_KVM_VCORE(r13)
lbz r7, HSTATE_PTID(r13)
li r0, 1
sld r0, r0, r7
addi r6, r5, VCORE_NAPPING_THREADS 1: lwarx r3, 0, r6
or r3, r3, r0
stwcx. r3, 0, r6
bne 1b /* order napping_threads update vs testing entry_exit_map */
isync
li r12, 0
lwz r7, VCORE_ENTRY_EXIT(r5)
cmpwi r7, 0x100
bge kvm_novcpu_exit /* another thread already exiting */
li r3, NAPPING_NOVCPU
stb r3, HSTATE_NAPPING(r13)
li r3, 0/* Don't wake on privileged (OS) doorbell */
b kvm_do_nap
/* See if the wake reason means we need to exit */
cmpdi r3, 0
bge kvm_novcpu_exit
/* See if our timeslice has expired (HDEC is negative) */
mfspr r0, SPRN_HDEC
extsw r0, r0
li r12, BOOK3S_INTERRUPT_HV_DECREMENTER
cmpdi r0, 0
blt kvm_novcpu_exit
/* Got an IPI but other vcpus aren't yet exiting, must be a latecomer */ ld r4, HSTATE_KVM_VCPU(r13)
cmpdi r4, 0
beq kvmppc_primary_no_guest
/* Check the wake reason in SRR1 to see why we got here */
bl kvmppc_check_wake_reason /* *kvmppc_check_wake_reasoncouldinvokeaCroutine,butwe *havenovolatileregisterstorestorewhenwereturn.
*/
cmpdi r3, 0
bge kvm_no_guest
/* get vcore pointer, NULL if we have nothing to run */ ld r5,HSTATE_KVM_VCORE(r13)
cmpdi r5,0 /* if we have no vcore to run, go back to sleep */
beq kvm_no_guest
kvm_secondary_got_guest:
// About to go to guest, clear saved SRR1
li r0, 0
std r0, 32(r1)
/* Set HSTATE_DSCR(r13) to something sensible */ ld r6, PACA_DSCR_DEFAULT(r13)
std r6, HSTATE_DSCR(r13)
/* On thread 0 of a subcore, set HDEC to max */
lbz r4, HSTATE_PTID(r13)
cmpwi r4, 0
bne 63f
lis r6,0x7fff /* MAX_INT@h */
mtspr SPRN_HDEC, r6 /* and set per-LPAR registers, if doing dynamic micro-threading */ ld r6, HSTATE_SPLIT_MODE(r13)
cmpdi r6, 0
beq 63f ld r0, KVM_SPLIT_RPR(r6)
mtspr SPRN_RPR, r0 ld r0, KVM_SPLIT_PMMAR(r6)
mtspr SPRN_PMMAR, r0 ld r0, KVM_SPLIT_LDBAR(r6)
mtspr SPRN_LDBAR, r0
isync 63: /* Order load of vcpu after load of vcore */
lwsync ld r4, HSTATE_KVM_VCPU(r13)
bl kvmppc_hv_entry
/* Back from the guest, go back to nap */ /* Clear our vcpu and vcore pointers so we don't come back in early */
li r0, 0
std r0, HSTATE_KVM_VCPU(r13) /* *OnceweclearHSTATE_KVM_VCORE(r13),thecodein *kvmppc_run_core()isgoingtoassumethatallourvcpu *stateisvisibleinmemory.Thislwsyncmakessure *thatthatistrue.
*/
lwsync
std r0, HSTATE_KVM_VCORE(r13)
/* *POWER7/POWER8host->guestpartitionswitchcode. *Wedon'thavetolockagainstconcurrenttlbies, *butwedohavetocoordinateacrosshardwarethreads.
*/ /* Set bit in entry map iff exit map is zero. */
li r7, 1
lbz r6, HSTATE_PTID(r13)
sld r7, r7, r6
addi r8, r5, VCORE_ENTRY_EXIT 21: lwarx r3, 0, r8
cmpwi r3, 0x100 /* any threads starting to exit? */
bge secondary_too_late /* if so we're too late to the party */
or r3, r3, r7
stwcx. r3, 0, r8
bne 21b
lwz r7,KVM_LPID(r9) ld r6,KVM_SDR1(r9)
li r0,LPID_RSVD /* switch to reserved LPID */
mtspr SPRN_LPID,r0
ptesync
mtspr SPRN_SDR1,r6 /* switch to partition page table */
mtspr SPRN_LPID,r7
isync
/* See if we need to flush the TLB. */
mr r3, r9 /* kvm pointer */
lhz r4, PACAPACAINDEX(r13) /* physical cpu number */
li r5, 0/* nested vcpu pointer */
bl kvmppc_check_need_tlb_flush
nop ld r5, HSTATE_KVM_VCORE(r13)
/* Load guest PCR value to select appropriate compat mode */ 37: ld r7, VCORE_PCR(r5)
LOAD_REG_IMMEDIATE(r6, PCR_MASK)
cmpld r7, r6
beq 38f
or r7, r7, r6
mtspr SPRN_PCR, r7 38:
BEGIN_FTR_SECTION /* DPDES and VTB are shared between threads */ ld r8, VCORE_DPDES(r5) ld r7, VCORE_VTB(r5)
mtspr SPRN_DPDES, r8
mtspr SPRN_VTB, r7
END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
/* Mark the subcore state as inside guest */
bl kvmppc_subcore_enter_guest
nop ld r5, HSTATE_KVM_VCORE(r13) ld r4, HSTATE_KVM_VCPU(r13)
li r0,1
stb r0,VCORE_IN_GUEST(r5) /* signal secondaries to continue */
/* Do we have a guest vcpu to run? */ 10: cmpdi r4, 0
beq kvmppc_primary_no_guest
kvmppc_got_guest: /* Increment yield count if they have a VPA */ ld r3, VCPU_VPA(r4)
cmpdi r3, 0
beq 25f
li r6, LPPACA_YIELDCOUNT
LWZX_BE r5, r3, r6
addi r5, r5, 1
STWX_BE r5, r3, r6
li r6, 1
stb r6, VCPU_VPA_DIRTY(r4) 25:
/* Save HEIR (HV emulation assist reg) in emul_inst
if this is an HEI (HV emulation interrupt, e40) */
li r3,KVM_INST_FETCH_FAILED
std r3,VCPU_LAST_INST(r9)
cmpwi r12,BOOK3S_INTERRUPT_H_EMUL_ASSIST
bne 11f
mfspr r3,SPRN_HEIR 11: std r3,VCPU_HEIR(r9)
/* these are volatile across C function calls */
mfctr r3
mfxer r4
std r3, VCPU_CTR(r9)
std r4, VCPU_XER(r9)
/* Save more register state */
mfdar r3
mfdsisr r4
std r3, VCPU_DAR(r9)
stw r4, VCPU_DSISR(r9)
/* If this is a page table miss then see if it's theirs or ours */
cmpwi r12, BOOK3S_INTERRUPT_H_DATA_STORAGE
beq kvmppc_hdsi
std r3, VCPU_FAULT_DAR(r9)
stw r4, VCPU_FAULT_DSISR(r9)
cmpwi r12, BOOK3S_INTERRUPT_H_INST_STORAGE
beq kvmppc_hisi
/* See if this is a leftover HDEC interrupt */
cmpwi r12,BOOK3S_INTERRUPT_HV_DECREMENTER
bne 2f
mfspr r3,SPRN_HDEC
extsw r3, r3
cmpdi r3,0
mr r4,r9
bge fast_guest_return 2: /* See if this is an hcall we can handle in real mode */
cmpwi r12,BOOK3S_INTERRUPT_SYSCALL
beq hcall_try_real_mode
/* Hypervisor doorbell - exit only if host IPI flag set */
cmpwi r12, BOOK3S_INTERRUPT_H_DOORBELL
bne 3f
lbz r0, HSTATE_HOST_IPI(r13)
cmpwi r0, 0
beq maybe_reenter_guest
b guest_exit_cont 3: /* If it's a hypervisor facility unavailable interrupt, save HFSCR */
cmpwi r12, BOOK3S_INTERRUPT_H_FAC_UNAVAIL
bne 14f
mfspr r3, SPRN_HFSCR
std r3, VCPU_HFSCR(r9)
b guest_exit_cont 14: /* External interrupt ? */
cmpwi r12, BOOK3S_INTERRUPT_EXTERNAL
beq kvmppc_guest_external /* See if it is a machine check */
cmpwi r12, BOOK3S_INTERRUPT_MACHINE_CHECK
beq machine_check_realmode /* Or a hypervisor maintenance interrupt */
cmpwi r12, BOOK3S_INTERRUPT_HMI
beq hmi_realmode
/* For hash guest, read the guest SLB and save it away */
li r5, 0
lwz r0,VCPU_SLB_NR(r9) /* number of entries in SLB */
mtctr r0
li r6,0
addi r7,r9,VCPU_SLB 1: slbmfee r8,r6
andis. r0,r8,SLB_ESID_V@h
beq 2f
add r8,r8,r6 /* put index in */
slbmfev r3,r6
std r8,VCPU_SLB_E(r7)
std r3,VCPU_SLB_V(r7)
addi r7,r7,VCPU_SLB_SIZE
addi r5,r5,1 2: addi r6,r6,1
bdnz 1b /* Finally clear out the SLB */
li r0,0
slbmte r0,r0
PPC_SLBIA(6)
ptesync
stw r5,VCPU_SLB_MAX(r9)
/* Save DEC */ /* Do this before kvmhv_commence_exit so we know TB is guest TB */ ld r3, HSTATE_KVM_VCORE(r13)
mfspr r5,SPRN_DEC
mftb r6
extsw r5,r5 16: add r5,r5,r6
std r5,VCPU_DEC_EXPIRES(r9)
/* Increment exit count, poke other threads to exit */
mr r3, r12
bl kvmhv_commence_exit
nop ld r9, HSTATE_KVM_VCPU(r13)
/* Stop others sending VCPU interrupts to this physical CPU */
li r0, -1
stw r0, VCPU_CPU(r9)
stw r0, VCPU_THREAD_CPU(r9)
/* Save guest CTRL register, set runlatch to 1 if it was clear */
mfspr r6,SPRN_CTRLF
stw r6,VCPU_CTRL(r9)
andi. r0,r6,1
bne 4f
li r6,1
mtspr SPRN_CTRLT,r6 4: /* *SavetheguestPURR/SPURR
*/
mfspr r5,SPRN_PURR
mfspr r6,SPRN_SPURR ld r7,VCPU_PURR(r9) ld r8,VCPU_SPURR(r9)
std r5,VCPU_PURR(r9)
std r6,VCPU_SPURR(r9)
subf r5,r7,r5
subf r6,r8,r6
/* Increment yield count if they have a VPA */ ld r8, VCPU_VPA(r9) /* do they have a VPA? */
cmpdi r8, 0
beq 25f
li r4, LPPACA_YIELDCOUNT
LWZX_BE r3, r8, r4
addi r3, r3, 1
STWX_BE r3, r8, r4
li r3, 1
stb r3, VCPU_VPA_DIRTY(r9) 25: /* Save PMU registers if requested */ /* r8 and cr0.eq are live here */
mr r3, r9
li r4, 1
beq 21f /* if no VPA, save PMU stuff anyway */
lbz r4, LPPACA_PMCINUSE(r8) 21: bl kvmhv_save_guest_pmu ld r9, HSTATE_KVM_VCPU(r13)
/* *POWER7/POWER8guest->hostpartitionswitchcode. *Wedon'thavetolockagainsttlbiesbutwedo *havetocoordinatethehardwarethreads. *HereSTACK_SLOT_TRAP(r1)containsthetrapnumber.
*/
kvmhv_switch_to_host: /* Secondary threads wait for primary to do partition switch */ ld r5,HSTATE_KVM_VCORE(r13) ld r4,VCORE_KVM(r5) /* pointer to struct kvm */
lbz r3,HSTATE_PTID(r13)
cmpwi r3,0
beq 15f
HMT_LOW 13: lbz r3,VCORE_IN_GUEST(r5)
cmpwi r3,0
bne 13b
HMT_MEDIUM
b 16f
/* Primary thread waits for all the secondaries to exit guest */ 15: lwz r3,VCORE_ENTRY_EXIT(r5)
rlwinm r0,r3,32-8,0xff
clrldi r3,r3,56
cmpw r3,r0
bne 15b
isync
/* Did we actually switch to the guest at all? */
lbz r6, VCORE_IN_GUEST(r5)
cmpwi r6, 0
beq 19f
/* Primary thread switches back to host partition */
lwz r7,KVM_HOST_LPID(r4) ld r6,KVM_HOST_SDR1(r4)
li r8,LPID_RSVD /* switch to reserved LPID */
mtspr SPRN_LPID,r8
ptesync
mtspr SPRN_SDR1,r6 /* switch to host page table */
mtspr SPRN_LPID,r7
isync
BEGIN_FTR_SECTION /* DPDES and VTB are shared between threads */
mfspr r7, SPRN_DPDES
mfspr r8, SPRN_VTB
std r7, VCORE_DPDES(r5)
std r8, VCORE_VTB(r5) /* clear DPDES so we don't get guest doorbells in the host */
li r8, 0
mtspr SPRN_DPDES, r8
END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
.balign 32
.global kvm_flush_link_stack
kvm_flush_link_stack: /* Save LR into r0 */
mflr r0
/* Flush the link stack. On Power8 it's up to 32 entries in size. */
.rept 32
bl .+4
.endr
/* And on Power9 it's up to 64. */
BEGIN_FTR_SECTION
.rept 32
bl .+4
.endr
END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300)
/* Restore LR */
mtlr r0
blr
kvmppc_guest_external: /* External interrupt, first check for host_ipi. If this is *set,weknowthehostwantsusoutsolet'sdoitnow
*/
bl CFUNC(kvmppc_read_intr)
/* *Restoretheactivevolatileregistersafterreturningfrom *aCfunction.
*/ ld r9, HSTATE_KVM_VCPU(r13)
li r12, BOOK3S_INTERRUPT_EXTERNAL
3: ld r5, VCPU_KVM(r9) /* not relocated, use VRMA */ ld r5, KVM_VRMA_SLB_V(r5)
b 4b
/* If this is for emulated MMIO, load the instruction word */ 2: li r8, KVM_INST_FETCH_FAILED /* In case lwz faults */
/* Set guest mode to 'jump over instruction' so if lwz faults
* we'll just continue at the next IP. */
li r0, KVM_GUEST_MODE_SKIP
stb r0, HSTATE_IN_GUEST(r13)
/* Do the access with MSR:DR enabled */
mfmsr r3
ori r4, r3, MSR_DR /* Enable paging for data */
mtmsrd r4
lwz r8, 0(r10)
mtmsrd r3
/* Store the result */
std r8, VCPU_LAST_INST(r9)
/* Unset guest mode. */
li r0, KVM_GUEST_MODE_HOST_HV
stb r0, HSTATE_IN_GUEST(r13)
b guest_exit_cont
/* *SimilarlyforanHISI,reflectittotheguestasanISIunless *itisanHPTEnotfoundfaultforapagethatwehavepagedout.
*/
kvmppc_hisi:
andis. r0, r11, SRR1_ISI_NOPT@h
beq 1f
andi. r0, r11, MSR_IR /* instruction relocation enabled? */
beq 3f
clrrdi r0, r10, 28
PPC_SLBFEE_DOT(R5, R0) /* if so, look up SLB */
li r0, BOOK3S_INTERRUPT_INST_SEGMENT
bne 7f /* if no SLB entry found */ 4: /* Search the hash table. */
mr r3, r9 /* vcpu pointer */
mr r4, r10
mr r6, r11
li r7, 0/* instruction fault */
bl CFUNC(kvmppc_hpte_hv_fault) ld r9, HSTATE_KVM_VCPU(r13) ld r10, VCPU_PC(r9) ld r11, VCPU_MSR(r9)
li r12, BOOK3S_INTERRUPT_H_INST_STORAGE
cmpdi r3, 0/* retry the instruction */
beq fast_interrupt_c_return
cmpdi r3, -1/* handle in kernel mode */
beq guest_exit_cont
/* Synthesize an ISI (or ISegI) for the guest */
mr r11, r3 1: li r0, BOOK3S_INTERRUPT_INST_STORAGE 7: mtspr SPRN_SRR0, r10
mtspr SPRN_SRR1, r11
mr r10, r0
bl kvmppc_msr_interrupt
b fast_interrupt_c_return
3: ld r6, VCPU_KVM(r9) /* not relocated, use VRMA */ ld r5, KVM_VRMA_SLB_V(r6)
b 4b
/* *Trytohandleanhcallinrealmode. *Returnstotheguestifwehandleit,orcontinuesonupto *thekernelifwecan't(i.e.ifwedon'thaveahandlerfor *it,orifthehandlerreturnsH_TOO_HARD). * *r5-r8containhcallargs, *r9=vcpu,r10=pc,r11=msr,r12=trap,r13=paca
*/
hcall_try_real_mode: ld r3,VCPU_GPR(R3)(r9)
andi. r0,r11,MSR_PR /* sc 1 from userspace - reflect to guest syscall */
bne sc_1_fast_return
clrrdi r3,r3,2
cmpldi r3,hcall_real_table_end - hcall_real_table
bge guest_exit_cont /* See if this hcall is enabled for in-kernel handling */ ld r4, VCPU_KVM(r9)
srdi r0, r3, 8/* r0 = (r3 / 4) >> 6 */
sldi r0, r0, 3/* index into kvm->arch.enabled_hcalls[] */
add r4, r4, r0 ld r0, KVM_ENABLED_HCALLS(r4)
rlwinm r4, r3, 32-2, 0x3f /* r4 = (r3 / 4) & 0x3f */
srd r0, r0, r4
andi. r0, r0, 1
beq guest_exit_cont /* Get pointer to handler, if any, and call it */
LOAD_REG_ADDR(r4, hcall_real_table)
lwax r3,r3,r4
cmpwi r3,0
beq guest_exit_cont
add r12,r3,r4
mtctr r12
mr r3,r9 /* get vcpu pointer */ ld r4,VCPU_GPR(R4)(r9)
bctrl
cmpdi r3,H_TOO_HARD
beq hcall_real_fallback ld r4,HSTATE_KVM_VCPU(r13)
std r3,VCPU_GPR(R3)(r4) ld r10,VCPU_PC(r4) ld r11,VCPU_MSR(r4)
b fast_guest_return
sc_1_fast_return:
mtspr SPRN_SRR0,r10
mtspr SPRN_SRR1,r11
li r10, BOOK3S_INTERRUPT_SYSCALL
bl kvmppc_msr_interrupt
mr r4,r9
b fast_guest_return
/* We've attempted a real mode hcall, but it's punted it back *touserspace.Weneedtorestoresomeclobberedvolatiles
* before resuming the pass-it-to-qemu path */
hcall_real_fallback:
li r12,BOOK3S_INTERRUPT_SYSCALL ld r9, HSTATE_KVM_VCPU(r13)
_GLOBAL(kvmppc_h_cede) /* r3 = vcpu pointer, r11 = msr, r13 = paca */
ori r11,r11,MSR_EE
std r11,VCPU_MSR(r3)
li r0,1
stb r0,VCPU_CEDED(r3)
sync /* order setting ceded vs. testing prodded */
lbz r5,VCPU_PRODDED(r3)
cmpwi r5,0
bne kvm_cede_prodded
li r12,0/* set trap to 0 to say hcall is handled */
stw r12,VCPU_TRAP(r3)
li r0,H_SUCCESS
std r0,VCPU_GPR(R3)(r3)
/* *Setourbitinthebitmaskofnappingthreadsunlessallthe *otherthreadsarealreadynapping,inwhichcasewesendthis *uptothehost.
*/ ld r5,HSTATE_KVM_VCORE(r13)
lbz r6,HSTATE_PTID(r13)
lwz r8,VCORE_ENTRY_EXIT(r5)
clrldi r8,r8,56
li r0,1
sld r0,r0,r6
addi r6,r5,VCORE_NAPPING_THREADS 31: lwarx r4,0,r6
or r4,r4,r0
cmpw r4,r8
beq kvm_cede_exit
stwcx. r4,0,r6
bne 31b /* order napping_threads update vs testing entry_exit_map */
isync
li r0,NAPPING_CEDE
stb r0,HSTATE_NAPPING(r13)
lwz r7,VCORE_ENTRY_EXIT(r5)
cmpwi r7,0x100
bge 33f /* another thread already exiting */
li r0,1
stb r0,HSTATE_HWTHREAD_REQ(r13)
mfspr r5,SPRN_LPCR
ori r5,r5,LPCR_PECE0 | LPCR_PECE1
BEGIN_FTR_SECTION
ori r5, r5, LPCR_PECEDH
rlwimi r5, r3, 0, LPCR_PECEDP
END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
kvm_nap_sequence: /* desired LPCR value in r5 */
li r3, PNV_THREAD_NAP
mtspr SPRN_LPCR,r5
isync
bl isa206_idle_insn_mayloss
li r0,1
mtspr SPRN_CTRLT, r0
mtspr SPRN_SRR1, r3
li r0, 0
stb r0, PACA_FTRACE_ENABLED(r13)
li r0, KVM_HWTHREAD_IN_KVM
stb r0, HSTATE_HWTHREAD_STATE(r13)
lbz r0, HSTATE_NAPPING(r13)
cmpwi r0, NAPPING_CEDE
beq kvm_end_cede
cmpwi r0, NAPPING_NOVCPU
beq kvm_novcpu_wakeup
cmpwi r0, NAPPING_UNSPLIT
beq kvm_unsplit_wakeup
twi 31,0,0/* Nap state must not be zero */
33: mr r4, r3
li r3, 0
li r12, 0
b 34f
kvm_end_cede: /* Woken by external or decrementer interrupt */
/* get vcpu pointer */ ld r4, HSTATE_KVM_VCPU(r13)
/* clear our bit in vcore->napping_threads */ 34: ld r5,HSTATE_KVM_VCORE(r13)
lbz r7,HSTATE_PTID(r13)
li r0,1
sld r0,r0,r7
addi r6,r5,VCORE_NAPPING_THREADS 32: lwarx r7,0,r6
andc r7,r7,r0
stwcx. r7,0,r6
bne 32b
li r0,0
stb r0,HSTATE_NAPPING(r13)
/* See if the wake reason saved in r3 means we need to exit */
stw r12, VCPU_TRAP(r4)
mr r9, r4
cmpdi r3, 0
bgt guest_exit_cont
b maybe_reenter_guest
/* cede when already previously prodded case */
kvm_cede_prodded:
li r0,0
stb r0,VCPU_PRODDED(r3)
sync /* order testing prodded vs. clearing ceded */
stb r0,VCPU_CEDED(r3)
li r3,H_SUCCESS
blr
/* we've ceded but we want to give control to the host */
kvm_cede_exit: ld r9, HSTATE_KVM_VCPU(r13)
b guest_exit_cont
/* Try to do machine check recovery in real mode */
machine_check_realmode:
mr r3, r9 /* get vcpu pointer */
bl kvmppc_realmode_machine_check
nop /* all machine checks go to virtual mode for further handling */ ld r9, HSTATE_KVM_VCPU(r13)
li r12, BOOK3S_INTERRUPT_MACHINE_CHECK
b guest_exit_cont
/* *Checkthereasonwewokefromnap,andtakeappropriateaction. *Returns(inr3): *0ifnothingneedstobedone *1ifsomethinghappenedthatneedstobehandledbythehost *-1iftherewasaguestwakeup(IPIormsgsnd) *-2ifwehandledaPCIpassthroughinterrupt(returnedby *kvmppc_read_intronly) * *Alsosetsr12totheinterruptvectorforanyinterruptthatneeds *tobehandlednowbythehost(0x500forexternalinterrupt),orzero. *Modifiesallvolatileregisters(sinceitmaycallaCfunction). *Thisroutinecallskvmppc_read_intr,aCfunction,ifanexternal *interruptispending.
*/
SYM_FUNC_START_LOCAL(kvmppc_check_wake_reason)
mfspr r6, SPRN_SRR1
BEGIN_FTR_SECTION
rlwinm r6, r6, 45-31, 0xf /* extract wake reason field (P8) */
FTR_SECTION_ELSE
rlwinm r6, r6, 45-31, 0xe /* P7 wake reason field is 3 bits */
ALT_FTR_SECTION_END_IFSET(CPU_FTR_ARCH_207S)
cmpwi r6, 8/* was it an external interrupt? */
beq 7f /* if so, see what it was */
li r3, 0
li r12, 0
cmpwi r6, 6/* was it the decrementer? */
beq 0f
BEGIN_FTR_SECTION
cmpwi r6, 5/* privileged doorbell? */
beq 0f
cmpwi r6, 3/* hypervisor doorbell? */
beq 3f
END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
cmpwi r6, 0xa /* Hypervisor maintenance ? */
beq 4f
li r3, 1/* anything else, return 1 */ 0: blr
/* hypervisor doorbell */ 3: li r12, BOOK3S_INTERRUPT_H_DOORBELL
/* *Clearthedoorbellaswewillinvokethehandler *explicitlyintheguestexitpath.
*/
lis r6, (PPC_DBELL_SERVER << (63-36))@h
PPC_MSGCLR(6) /* see if it's a host IPI */
li r3, 1
lbz r0, HSTATE_HOST_IPI(r13)
cmpwi r0, 0
bnelr /* if not, return -1 */
li r3, -1
blr
/* Woken up due to Hypervisor maintenance interrupt */ 4: li r12, BOOK3S_INTERRUPT_HMI
li r3, 1
blr
/* external interrupt - create a stack frame so we can call C */ 7: mflr r0
std r0, PPC_LR_STKOFF(r1)
stdu r1, -PPC_MIN_STKFRM(r1)
bl CFUNC(kvmppc_read_intr)
nop
li r12, BOOK3S_INTERRUPT_EXTERNAL
cmpdi r3, 1
ble 1f
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM /* *SavetransactionalstateandTM-relatedregisters. *Calledwithr3pointingtothevcpustructandr4containing *theguestMSRvalue. *r5isnon-zeroiffnon-volatileregisterstateneedstobemaintained. *Ifr5==0,thiscanmodifyallcheckpointedregisters,but *restoresr1andr2beforeexit.
*/
_GLOBAL_TOC(kvmppc_save_tm_hv)
EXPORT_SYMBOL_GPL(kvmppc_save_tm_hv) /* See if we need to handle fake suspend mode */
BEGIN_FTR_SECTION
b __kvmppc_save_tm
END_FTR_SECTION_IFCLR(CPU_FTR_P9_TM_HV_ASSIST)
lbz r0, HSTATE_FAKE_SUSPEND(r13) /* Were we fake suspended? */
cmpwi r0, 0
beq __kvmppc_save_tm
/* The following code handles the fake_suspend = 1 case */
mflr r0
std r0, PPC_LR_STKOFF(r1)
stdu r1, -TM_FRAME_SIZE(r1)
/* Turn on TM. */
mfmsr r8
li r0, 1
rldimi r8, r0, MSR_TM_LG, 63-MSR_TM_LG
mtmsrd r8
rldicl. r8, r8, 64 - MSR_TS_S_LG, 62/* Did we actually hrfid? */
beq 4f
BEGIN_FTR_SECTION
bl pnv_power9_force_smt4_catch
END_FTR_SECTION_IFSET(CPU_FTR_P9_TM_XER_SO_BUG)
nop
/* *It'spossiblethattreclaim.maymodifyregisters,ifwehavelost *trackoffake-suspendstateintheguestduetoitusingrfscv. *Saveandrestoreregistersincasethisoccurs.
*/
mfspr r3, SPRN_DSCR
mfspr r4, SPRN_XER
mfspr r5, SPRN_AMR /* SPRN_TAR would need to be saved here if the kernel ever used it */
mfcr r12
SAVE_NVGPRS(r1)
SAVE_GPR(2, r1)
SAVE_GPR(3, r1)
SAVE_GPR(4, r1)
SAVE_GPR(5, r1)
stw r12, 8(r1)
std r1, HSTATE_HOST_R1(r13)
/* We have to treclaim here because that's the only way to do S->N */
li r3, TM_CAUSE_KVM_RESCHED
TRECLAIM(R3)
4:
mfspr r3, SPRN_PSSCR /* PSSCR_FAKE_SUSPEND is a write-only bit, but clear it anyway */
li r0, PSSCR_FAKE_SUSPEND
andc r3, r3, r0
mtspr SPRN_PSSCR, r3
/* Don't save TEXASR, use value from last exit in real suspend state */ ld r9, HSTATE_KVM_VCPU(r13)
mfspr r5, SPRN_TFHAR
mfspr r6, SPRN_TFIAR
std r5, VCPU_TFHAR(r9)
std r6, VCPU_TFIAR(r9)
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.