Re: [PATCH 08/27] Add SLB switching code for entry/exit
From: Michael Neuling <hidden>
Date: 2009-11-02 09:39:43
Also in:
kvm
quoted
quoted
This is the really low level of guest entry/exit code. Book3s_64 has an SLB, which stores all ESID -> VSID mappings we're currently aware of. The segments in the guest differ from the ones on the host, so we need to switch the SLB to tell the MMU that we're in a new context. So we store a shadow of the guest's SLB in the PACA, switch to that on entry and only restore bolted entries on exit, leaving the rest to the Linux SLB fault handler. That way we get a really clean way of switching the SLB. Signed-off-by: Alexander Graf <redacted> --- arch/powerpc/kvm/book3s_64_slb.S | 277 ++++++++++++++++++++++++++++ ++++++++++quoted
1 files changed, 277 insertions(+), 0 deletions(-) create mode 100644 arch/powerpc/kvm/book3s_64_slb.Sdiff --git a/arch/powerpc/kvm/book3s_64_slb.S b/arch/powerpc/kvm/book3s_64_slb.Squoted
new file mode 100644 index 0000000..00a8367--- /dev/null +++ b/arch/powerpc/kvm/book3s_64_slb.S@@ -0,0 +1,277 @@ +/* + * This program is free software; you can redistribute it and/ormodify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright SUSE Linux Products GmbH 2009 + * + * Authors: Alexander Graf [off-list ref] + */ + +/ *** *** ************************************************************************quoted
+ **quoted
+ * Entry code*quoted
+ **quoted
+ *** *** ***********************************************************************/quoted
+ +.global kvmppc_handler_trampoline_enter +kvmppc_handler_trampoline_enter: + + /* Required state: + * + * MSR = ~IR|DR + * R13 = PACA + * R9 = guest IP + * R10 = guest MSR + * R11 = free + * R12 = free + * PACA[PACA_EXMC + EX_R9] = guest R9 + * PACA[PACA_EXMC + EX_R10] = guest R10 + * PACA[PACA_EXMC + EX_R11] = guest R11 + * PACA[PACA_EXMC + EX_R12] = guest R12 + * PACA[PACA_EXMC + EX_R13] = guest R13 + * PACA[PACA_EXMC + EX_CCR] = guest CR + * PACA[PACA_EXMC + EX_R3] = guest XER + */ + + mtsrr0 r9 + mtsrr1 r10 + + mtspr SPRN_SPRG_SCRATCH0, r0 + + /* Remove LPAR shadow entries */ + +#if SLB_NUM_BOLTED == 3You could alternatively check the persistent entry in the slb_shawdow buffer. This would give you a run time check. Not sure what's best though.Well we're in the hot path here, so anything using as few registers as possible and being simple is the best :-). I'd guess the more we are clever at compile time the better.
Yeah, I tend to agree.
quoted
quoted
+ + ld r12, PACA_SLBSHADOWPTR(r13) + ld r10, 0x10(r12) + ld r11, 0x18(r12)Can you define something in asm-offsets.c for these magic constants 0x10 and 0x18. Similarly below.quoted
+ /* Invalid? Skip. */ + rldicl. r0, r10, 37, 63 + beq slb_entry_skip_1 + xoris r9, r10, SLB_ESID_V@h + std r9, 0x10(r12) +slb_entry_skip_1: + ld r9, 0x20(r12) + /* Invalid? Skip. */ + rldicl. r0, r9, 37, 63 + beq slb_entry_skip_2 + xoris r9, r9, SLB_ESID_V@h + std r9, 0x20(r12) +slb_entry_skip_2: + ld r9, 0x30(r12) + /* Invalid? Skip. */ + rldicl. r0, r9, 37, 63 + beq slb_entry_skip_3 + xoris r9, r9, SLB_ESID_V@h + std r9, 0x30(r12)Can these 3 be made into a macro?Phew - dynamically generating jump points sounds rather hard. I can give it a try...quoted
quoted
+slb_entry_skip_3: + +#else +#error unknown number of bolted entries +#endif + + /* Flush SLB */ + + slbia + + /* r0 = esid & ESID_MASK */ + rldicr r10, r10, 0, 35 + /* r0 |= CLASS_BIT(VSID) */ + rldic r12, r11, 56 - 36, 36 + or r10, r10, r12 + slbie r10 + + isync + + /* Fill SLB with our shadow */ + + lbz r12, PACA_KVM_SLB_MAX(r13) + mulli r12, r12, 16 + addi r12, r12, PACA_KVM_SLB + add r12, r12, r13 + + /* for (r11 = kvm_slb; r11 < kvm_slb + kvm_slb_size; r11+=slb_entry) */ + li r11, PACA_KVM_SLB + add r11, r11, r13 + +slb_loop_enter: + + ld r10, 0(r11) + + rldicl. r0, r10, 37, 63 + beq slb_loop_enter_skip + + ld r9, 8(r11) + slbmte r9, r10If you're updating the first 3 slbs, you need to make sure the slb shadow is updated at the same timeWell - what happens if we don't? We'd get a segment fault when phyp stole our entry! So what? Let it fault, see the mapping is already there and get back in again :-).
The problem is you won't take the segment fault as PHYP may put a valid entry in there. PHYP will put back what's in the shadow buffer, which could be valid hence no segment fault.
quoted
(BTW dumb question: can we run this under PHYP?)Yes, I tested it on bare metal, phyp and a PS3.
Nice! Mikey