diff mbox

[04/27] KVM: PPC: Add generic segment switching code

Message ID 1271369518-11247-5-git-send-email-agraf@suse.de (mailing list archive)
State New, archived
Headers show

Commit Message

Alexander Graf April 15, 2010, 10:11 p.m. UTC
None
diff mbox

Patch

diff --git a/arch/powerpc/kvm/book3s_segment.S b/arch/powerpc/kvm/book3s_segment.S
new file mode 100644
index 0000000..778e3fc
--- /dev/null
+++ b/arch/powerpc/kvm/book3s_segment.S
@@ -0,0 +1,258 @@ 
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * 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 2010
+ *
+ * Authors: Alexander Graf <agraf@suse.de>
+ */
+
+/* Real mode helpers */
+
+#if defined(CONFIG_PPC_BOOK3S_64)
+
+#define GET_SHADOW_VCPU(reg)    \
+	addi    reg, r13, PACA_KVM_SVCPU
+
+#elif defined(CONFIG_PPC_BOOK3S_32)
+
+#define GET_SHADOW_VCPU(reg)    			\
+	tophys(reg, r2);       			\
+	lwz     reg, (THREAD + THREAD_KVM_SVCPU)(reg);	\
+	tophys(reg, reg)
+
+#endif
+
+/* Disable for nested KVM */
+#define USE_QUICK_LAST_INST
+
+
+/* Get helper functions for subarch specific functionality */
+
+#if defined(CONFIG_PPC_BOOK3S_64)
+#include "book3s_64_slb.S"
+#elif defined(CONFIG_PPC_BOOK3S_32)
+#include "book3s_32_sr.S"
+#endif
+
+/******************************************************************************
+ *                                                                            *
+ *                               Entry code                                   *
+ *                                                                            *
+ *****************************************************************************/
+
+.global kvmppc_handler_trampoline_enter
+kvmppc_handler_trampoline_enter:
+
+	/* Required state:
+	 *
+	 * MSR = ~IR|DR
+	 * R13 = PACA
+	 * R1 = host R1
+	 * R2 = host R2
+	 * R10 = guest MSR
+	 * all other volatile GPRS = free
+	 * SVCPU[CR] = guest CR
+	 * SVCPU[XER] = guest XER
+	 * SVCPU[CTR] = guest CTR
+	 * SVCPU[LR] = guest LR
+	 */
+
+	/* r3 = shadow vcpu */
+	GET_SHADOW_VCPU(r3)
+
+	/* Move SRR0 and SRR1 into the respective regs */
+	PPC_LL  r9, SVCPU_PC(r3)
+	mtsrr0	r9
+	mtsrr1	r10
+
+	/* Activate guest mode, so faults get handled by KVM */
+	li	r11, KVM_GUEST_MODE_GUEST
+	stb	r11, SVCPU_IN_GUEST(r3)
+
+	/* Switch to guest segment. This is subarch specific. */
+	LOAD_GUEST_SEGMENTS
+
+	/* Enter guest */
+
+	PPC_LL	r4, (SVCPU_CTR)(r3)
+	PPC_LL	r5, (SVCPU_LR)(r3)
+	lwz	r6, (SVCPU_CR)(r3)
+	lwz	r7, (SVCPU_XER)(r3)
+
+	mtctr	r4
+	mtlr	r5
+	mtcr	r6
+	mtxer	r7
+
+	PPC_LL	r0, (SVCPU_R0)(r3)
+	PPC_LL	r1, (SVCPU_R1)(r3)
+	PPC_LL	r2, (SVCPU_R2)(r3)
+	PPC_LL	r4, (SVCPU_R4)(r3)
+	PPC_LL	r5, (SVCPU_R5)(r3)
+	PPC_LL	r6, (SVCPU_R6)(r3)
+	PPC_LL	r7, (SVCPU_R7)(r3)
+	PPC_LL	r8, (SVCPU_R8)(r3)
+	PPC_LL	r9, (SVCPU_R9)(r3)
+	PPC_LL	r10, (SVCPU_R10)(r3)
+	PPC_LL	r11, (SVCPU_R11)(r3)
+	PPC_LL	r12, (SVCPU_R12)(r3)
+	PPC_LL	r13, (SVCPU_R13)(r3)
+
+	PPC_LL	r3, (SVCPU_R3)(r3)
+
+	RFI
+kvmppc_handler_trampoline_enter_end:
+
+
+
+/******************************************************************************
+ *                                                                            *
+ *                               Exit code                                    *
+ *                                                                            *
+ *****************************************************************************/
+
+.global kvmppc_handler_trampoline_exit
+kvmppc_handler_trampoline_exit:
+
+	/* Register usage at this point:
+	 *
+	 * SPRG_SCRATCH0  = guest R13
+	 * R12            = exit handler id
+	 * R13            = shadow vcpu - SHADOW_VCPU_OFF [=PACA on PPC64]
+	 * SVCPU.SCRATCH0 = guest R12
+	 * SVCPU.SCRATCH1 = guest CR
+	 *
+	 */
+
+	/* Save registers */
+
+	PPC_STL	r0, (SHADOW_VCPU_OFF + SVCPU_R0)(r13)
+	PPC_STL	r1, (SHADOW_VCPU_OFF + SVCPU_R1)(r13)
+	PPC_STL	r2, (SHADOW_VCPU_OFF + SVCPU_R2)(r13)
+	PPC_STL	r3, (SHADOW_VCPU_OFF + SVCPU_R3)(r13)
+	PPC_STL	r4, (SHADOW_VCPU_OFF + SVCPU_R4)(r13)
+	PPC_STL	r5, (SHADOW_VCPU_OFF + SVCPU_R5)(r13)
+	PPC_STL	r6, (SHADOW_VCPU_OFF + SVCPU_R6)(r13)
+	PPC_STL	r7, (SHADOW_VCPU_OFF + SVCPU_R7)(r13)
+	PPC_STL	r8, (SHADOW_VCPU_OFF + SVCPU_R8)(r13)
+	PPC_STL	r9, (SHADOW_VCPU_OFF + SVCPU_R9)(r13)
+	PPC_STL	r10, (SHADOW_VCPU_OFF + SVCPU_R10)(r13)
+	PPC_STL	r11, (SHADOW_VCPU_OFF + SVCPU_R11)(r13)
+
+	/* Restore R1/R2 so we can handle faults */
+	PPC_LL	r1, (SHADOW_VCPU_OFF + SVCPU_HOST_R1)(r13)
+	PPC_LL	r2, (SHADOW_VCPU_OFF + SVCPU_HOST_R2)(r13)
+
+	/* Save guest PC and MSR */
+	mfsrr0	r3
+	mfsrr1	r4
+
+	PPC_STL	r3, (SHADOW_VCPU_OFF + SVCPU_PC)(r13)
+	PPC_STL	r4, (SHADOW_VCPU_OFF + SVCPU_SHADOW_SRR1)(r13)
+
+	/* Get scratch'ed off registers */
+	mfspr	r9, SPRN_SPRG_SCRATCH0
+	PPC_LL	r8, (SHADOW_VCPU_OFF + SVCPU_SCRATCH0)(r13)
+	lwz	r7, (SHADOW_VCPU_OFF + SVCPU_SCRATCH1)(r13)
+
+	PPC_STL	r9, (SHADOW_VCPU_OFF + SVCPU_R13)(r13)
+	PPC_STL	r8, (SHADOW_VCPU_OFF + SVCPU_R12)(r13)
+	stw	r7, (SHADOW_VCPU_OFF + SVCPU_CR)(r13)
+
+	/* Save more register state  */
+
+	mfxer	r5
+	mfdar	r6
+	mfdsisr	r7
+	mfctr	r8
+	mflr	r9
+
+	stw	r5, (SHADOW_VCPU_OFF + SVCPU_XER)(r13)
+	PPC_STL	r6, (SHADOW_VCPU_OFF + SVCPU_FAULT_DAR)(r13)
+	stw	r7, (SHADOW_VCPU_OFF + SVCPU_FAULT_DSISR)(r13)
+	PPC_STL	r8, (SHADOW_VCPU_OFF + SVCPU_CTR)(r13)
+	PPC_STL	r9, (SHADOW_VCPU_OFF + SVCPU_LR)(r13)
+
+	/*
+	 * In order for us to easily get the last instruction,
+	 * we got the #vmexit at, we exploit the fact that the
+	 * virtual layout is still the same here, so we can just
+	 * ld from the guest's PC address
+	 */
+
+	/* We only load the last instruction when it's safe */
+	cmpwi	r12, BOOK3S_INTERRUPT_DATA_STORAGE
+	beq	ld_last_inst
+	cmpwi	r12, BOOK3S_INTERRUPT_PROGRAM
+	beq	ld_last_inst
+
+	b	no_ld_last_inst
+
+ld_last_inst:
+	/* Save off the guest instruction we're at */
+
+	/* In case lwz faults */
+	li	r0, KVM_INST_FETCH_FAILED
+
+#ifdef USE_QUICK_LAST_INST
+
+	/* Set guest mode to 'jump over instruction' so if lwz faults
+	 * we'll just continue at the next IP. */
+	li	r9, KVM_GUEST_MODE_SKIP
+	stb	r9, (SHADOW_VCPU_OFF + SVCPU_IN_GUEST)(r13)
+
+	/*    1) enable paging for data */
+	mfmsr	r9
+	ori	r11, r9, MSR_DR			/* Enable paging for data */
+	mtmsr	r11
+	sync
+	/*    2) fetch the instruction */
+	lwz	r0, 0(r3)
+	/*    3) disable paging again */
+	mtmsr	r9
+	sync
+
+#endif
+	stw	r0, (SHADOW_VCPU_OFF + SVCPU_LAST_INST)(r13)
+
+no_ld_last_inst:
+
+	/* Unset guest mode */
+	li	r9, KVM_GUEST_MODE_NONE
+	stb	r9, (SHADOW_VCPU_OFF + SVCPU_IN_GUEST)(r13)
+
+	/* Switch back to host MMU */
+	LOAD_HOST_SEGMENTS
+
+	/* Register usage at this point:
+	 *
+	 * R1       = host R1
+	 * R2       = host R2
+	 * R12      = exit handler id
+	 * R13      = shadow vcpu - SHADOW_VCPU_OFF [=PACA on PPC64]
+	 * SVCPU.*  = guest *
+	 *
+	 */
+
+	/* RFI into the highmem handler */
+	mfmsr	r7
+	ori	r7, r7, MSR_IR|MSR_DR|MSR_RI|MSR_ME	/* Enable paging */
+	mtsrr1	r7
+	/* Load highmem handler address */
+	PPC_LL	r8, (SHADOW_VCPU_OFF + SVCPU_VMHANDLER)(r13)
+	mtsrr0	r8
+
+	RFI
+kvmppc_handler_trampoline_exit_end:
+