xref: /OK3568_Linux_fs/kernel/arch/powerpc/kvm/book3s_rmhandlers.S (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun/* SPDX-License-Identifier: GPL-2.0-only */
2*4882a593Smuzhiyun/*
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Copyright SUSE Linux Products GmbH 2009
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * Authors: Alexander Graf <agraf@suse.de>
7*4882a593Smuzhiyun */
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun#include <asm/ppc_asm.h>
10*4882a593Smuzhiyun#include <asm/kvm_asm.h>
11*4882a593Smuzhiyun#include <asm/reg.h>
12*4882a593Smuzhiyun#include <asm/mmu.h>
13*4882a593Smuzhiyun#include <asm/page.h>
14*4882a593Smuzhiyun#include <asm/asm-offsets.h>
15*4882a593Smuzhiyun#include <asm/asm-compat.h>
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun#ifdef CONFIG_PPC_BOOK3S_64
18*4882a593Smuzhiyun#include <asm/exception-64s.h>
19*4882a593Smuzhiyun#endif
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun/*****************************************************************************
22*4882a593Smuzhiyun *                                                                           *
23*4882a593Smuzhiyun *        Real Mode handlers that need to be in low physical memory          *
24*4882a593Smuzhiyun *                                                                           *
25*4882a593Smuzhiyun ****************************************************************************/
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun#if defined(CONFIG_PPC_BOOK3S_64)
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun#ifdef PPC64_ELF_ABI_v2
30*4882a593Smuzhiyun#define FUNC(name) 		name
31*4882a593Smuzhiyun#else
32*4882a593Smuzhiyun#define FUNC(name) 		GLUE(.,name)
33*4882a593Smuzhiyun#endif
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun#elif defined(CONFIG_PPC_BOOK3S_32)
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun#define FUNC(name)		name
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun#define RFI_TO_KERNEL	RFI
40*4882a593Smuzhiyun#define RFI_TO_GUEST	RFI
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun.macro INTERRUPT_TRAMPOLINE intno
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun.global kvmppc_trampoline_\intno
45*4882a593Smuzhiyunkvmppc_trampoline_\intno:
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun	mtspr	SPRN_SPRG_SCRATCH0, r13		/* Save r13 */
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun	/*
50*4882a593Smuzhiyun	 * First thing to do is to find out if we're coming
51*4882a593Smuzhiyun	 * from a KVM guest or a Linux process.
52*4882a593Smuzhiyun	 *
53*4882a593Smuzhiyun	 * To distinguish, we check a magic byte in the PACA/current
54*4882a593Smuzhiyun	 */
55*4882a593Smuzhiyun	mfspr	r13, SPRN_SPRG_THREAD
56*4882a593Smuzhiyun	lwz	r13, THREAD_KVM_SVCPU(r13)
57*4882a593Smuzhiyun	/* PPC32 can have a NULL pointer - let's check for that */
58*4882a593Smuzhiyun	mtspr   SPRN_SPRG_SCRATCH1, r12		/* Save r12 */
59*4882a593Smuzhiyun	mfcr	r12
60*4882a593Smuzhiyun	cmpwi	r13, 0
61*4882a593Smuzhiyun	bne	1f
62*4882a593Smuzhiyun2:	mtcr	r12
63*4882a593Smuzhiyun	mfspr	r12, SPRN_SPRG_SCRATCH1
64*4882a593Smuzhiyun	mfspr	r13, SPRN_SPRG_SCRATCH0		/* r13 = original r13 */
65*4882a593Smuzhiyun	b	kvmppc_resume_\intno		/* Get back original handler */
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun1:	tophys(r13, r13)
68*4882a593Smuzhiyun	stw	r12, HSTATE_SCRATCH1(r13)
69*4882a593Smuzhiyun	mfspr	r12, SPRN_SPRG_SCRATCH1
70*4882a593Smuzhiyun	stw	r12, HSTATE_SCRATCH0(r13)
71*4882a593Smuzhiyun	lbz	r12, HSTATE_IN_GUEST(r13)
72*4882a593Smuzhiyun	cmpwi	r12, KVM_GUEST_MODE_NONE
73*4882a593Smuzhiyun	bne	..kvmppc_handler_hasmagic_\intno
74*4882a593Smuzhiyun	/* No KVM guest? Then jump back to the Linux handler! */
75*4882a593Smuzhiyun	lwz	r12, HSTATE_SCRATCH1(r13)
76*4882a593Smuzhiyun	b	2b
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun	/* Now we know we're handling a KVM guest */
79*4882a593Smuzhiyun..kvmppc_handler_hasmagic_\intno:
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun	/* Should we just skip the faulting instruction? */
82*4882a593Smuzhiyun	cmpwi	r12, KVM_GUEST_MODE_SKIP
83*4882a593Smuzhiyun	beq	kvmppc_handler_skip_ins
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun	/* Let's store which interrupt we're handling */
86*4882a593Smuzhiyun	li	r12, \intno
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun	/* Jump into the SLB exit code that goes to the highmem handler */
89*4882a593Smuzhiyun	b	kvmppc_handler_trampoline_exit
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun.endm
92*4882a593Smuzhiyun
93*4882a593SmuzhiyunINTERRUPT_TRAMPOLINE	BOOK3S_INTERRUPT_SYSTEM_RESET
94*4882a593SmuzhiyunINTERRUPT_TRAMPOLINE	BOOK3S_INTERRUPT_MACHINE_CHECK
95*4882a593SmuzhiyunINTERRUPT_TRAMPOLINE	BOOK3S_INTERRUPT_DATA_STORAGE
96*4882a593SmuzhiyunINTERRUPT_TRAMPOLINE	BOOK3S_INTERRUPT_INST_STORAGE
97*4882a593SmuzhiyunINTERRUPT_TRAMPOLINE	BOOK3S_INTERRUPT_EXTERNAL
98*4882a593SmuzhiyunINTERRUPT_TRAMPOLINE	BOOK3S_INTERRUPT_ALIGNMENT
99*4882a593SmuzhiyunINTERRUPT_TRAMPOLINE	BOOK3S_INTERRUPT_PROGRAM
100*4882a593SmuzhiyunINTERRUPT_TRAMPOLINE	BOOK3S_INTERRUPT_FP_UNAVAIL
101*4882a593SmuzhiyunINTERRUPT_TRAMPOLINE	BOOK3S_INTERRUPT_DECREMENTER
102*4882a593SmuzhiyunINTERRUPT_TRAMPOLINE	BOOK3S_INTERRUPT_SYSCALL
103*4882a593SmuzhiyunINTERRUPT_TRAMPOLINE	BOOK3S_INTERRUPT_TRACE
104*4882a593SmuzhiyunINTERRUPT_TRAMPOLINE	BOOK3S_INTERRUPT_PERFMON
105*4882a593SmuzhiyunINTERRUPT_TRAMPOLINE	BOOK3S_INTERRUPT_ALTIVEC
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun/*
108*4882a593Smuzhiyun * Bring us back to the faulting code, but skip the
109*4882a593Smuzhiyun * faulting instruction.
110*4882a593Smuzhiyun *
111*4882a593Smuzhiyun * This is a generic exit path from the interrupt
112*4882a593Smuzhiyun * trampolines above.
113*4882a593Smuzhiyun *
114*4882a593Smuzhiyun * Input Registers:
115*4882a593Smuzhiyun *
116*4882a593Smuzhiyun * R12            = free
117*4882a593Smuzhiyun * R13            = Shadow VCPU (PACA)
118*4882a593Smuzhiyun * HSTATE.SCRATCH0 = guest R12
119*4882a593Smuzhiyun * HSTATE.SCRATCH1 = guest CR
120*4882a593Smuzhiyun * SPRG_SCRATCH0  = guest R13
121*4882a593Smuzhiyun *
122*4882a593Smuzhiyun */
123*4882a593Smuzhiyunkvmppc_handler_skip_ins:
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun	/* Patch the IP to the next instruction */
126*4882a593Smuzhiyun	mfsrr0	r12
127*4882a593Smuzhiyun	addi	r12, r12, 4
128*4882a593Smuzhiyun	mtsrr0	r12
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun	/* Clean up all state */
131*4882a593Smuzhiyun	lwz	r12, HSTATE_SCRATCH1(r13)
132*4882a593Smuzhiyun	mtcr	r12
133*4882a593Smuzhiyun	PPC_LL	r12, HSTATE_SCRATCH0(r13)
134*4882a593Smuzhiyun	GET_SCRATCH0(r13)
135*4882a593Smuzhiyun
136*4882a593Smuzhiyun	/* And get back into the code */
137*4882a593Smuzhiyun	RFI_TO_KERNEL
138*4882a593Smuzhiyun#endif
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun/*
141*4882a593Smuzhiyun * Call kvmppc_handler_trampoline_enter in real mode
142*4882a593Smuzhiyun *
143*4882a593Smuzhiyun * On entry, r4 contains the guest shadow MSR
144*4882a593Smuzhiyun * MSR.EE has to be 0 when calling this function
145*4882a593Smuzhiyun */
146*4882a593Smuzhiyun_GLOBAL_TOC(kvmppc_entry_trampoline)
147*4882a593Smuzhiyun	mfmsr	r5
148*4882a593Smuzhiyun	LOAD_REG_ADDR(r7, kvmppc_handler_trampoline_enter)
149*4882a593Smuzhiyun	toreal(r7)
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun	li	r6, MSR_IR | MSR_DR
152*4882a593Smuzhiyun	andc	r6, r5, r6	/* Clear DR and IR in MSR value */
153*4882a593Smuzhiyun	/*
154*4882a593Smuzhiyun	 * Set EE in HOST_MSR so that it's enabled when we get into our
155*4882a593Smuzhiyun	 * C exit handler function.
156*4882a593Smuzhiyun	 */
157*4882a593Smuzhiyun	ori	r5, r5, MSR_EE
158*4882a593Smuzhiyun	mtsrr0	r7
159*4882a593Smuzhiyun	mtsrr1	r6
160*4882a593Smuzhiyun	RFI_TO_KERNEL
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun#include "book3s_segment.S"
163