Commit | Line | Data |
---|---|---|
c862125c AG |
1 | /* |
2 | * This program is free software; you can redistribute it and/or modify | |
3 | * it under the terms of the GNU General Public License, version 2, as | |
4 | * published by the Free Software Foundation. | |
5 | * | |
6 | * This program is distributed in the hope that it will be useful, | |
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
9 | * GNU General Public License for more details. | |
10 | * | |
11 | * You should have received a copy of the GNU General Public License | |
12 | * along with this program; if not, write to the Free Software | |
13 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
14 | * | |
15 | * Copyright SUSE Linux Products GmbH 2009 | |
16 | * | |
17 | * Authors: Alexander Graf <agraf@suse.de> | |
18 | */ | |
19 | ||
20 | #include <asm/ppc_asm.h> | |
21 | #include <asm/kvm_asm.h> | |
22 | #include <asm/reg.h> | |
177339d7 | 23 | #include <asm/mmu.h> |
c862125c AG |
24 | #include <asm/page.h> |
25 | #include <asm/asm-offsets.h> | |
8c3a4e0b AG |
26 | |
27 | #ifdef CONFIG_PPC_BOOK3S_64 | |
c862125c | 28 | #include <asm/exception-64s.h> |
8c3a4e0b | 29 | #endif |
c862125c AG |
30 | |
31 | /***************************************************************************** | |
32 | * * | |
33 | * Real Mode handlers that need to be in low physical memory * | |
34 | * * | |
35 | ****************************************************************************/ | |
36 | ||
8c3a4e0b AG |
37 | #if defined(CONFIG_PPC_BOOK3S_64) |
38 | ||
8c3a4e0b AG |
39 | #define FUNC(name) GLUE(.,name) |
40 | ||
177339d7 | 41 | .globl kvmppc_skip_interrupt |
b01c8b54 PM |
42 | kvmppc_skip_interrupt: |
43 | /* | |
44 | * Here all GPRs are unchanged from when the interrupt happened | |
45 | * except for r13, which is saved in SPRG_SCRATCH0. | |
46 | */ | |
47 | mfspr r13, SPRN_SRR0 | |
48 | addi r13, r13, 4 | |
49 | mtspr SPRN_SRR0, r13 | |
50 | GET_SCRATCH0(r13) | |
51 | rfid | |
52 | b . | |
53 | ||
177339d7 | 54 | .globl kvmppc_skip_Hinterrupt |
b01c8b54 PM |
55 | kvmppc_skip_Hinterrupt: |
56 | /* | |
57 | * Here all GPRs are unchanged from when the interrupt happened | |
58 | * except for r13, which is saved in SPRG_SCRATCH0. | |
59 | */ | |
60 | mfspr r13, SPRN_HSRR0 | |
61 | addi r13, r13, 4 | |
62 | mtspr SPRN_HSRR0, r13 | |
63 | GET_SCRATCH0(r13) | |
64 | hrfid | |
65 | b . | |
8c3a4e0b | 66 | |
b01c8b54 | 67 | #elif defined(CONFIG_PPC_BOOK3S_32) |
8c3a4e0b | 68 | |
8c3a4e0b AG |
69 | #define FUNC(name) name |
70 | ||
c862125c AG |
71 | .macro INTERRUPT_TRAMPOLINE intno |
72 | ||
73 | .global kvmppc_trampoline_\intno | |
74 | kvmppc_trampoline_\intno: | |
75 | ||
b01c8b54 | 76 | mtspr SPRN_SPRG_SCRATCH0, r13 /* Save r13 */ |
c862125c AG |
77 | |
78 | /* | |
79 | * First thing to do is to find out if we're coming | |
80 | * from a KVM guest or a Linux process. | |
81 | * | |
8c3a4e0b | 82 | * To distinguish, we check a magic byte in the PACA/current |
c862125c | 83 | */ |
b01c8b54 PM |
84 | mfspr r13, SPRN_SPRG_THREAD |
85 | lwz r13, THREAD_KVM_SVCPU(r13) | |
86 | /* PPC32 can have a NULL pointer - let's check for that */ | |
87 | mtspr SPRN_SPRG_SCRATCH1, r12 /* Save r12 */ | |
c862125c | 88 | mfcr r12 |
b01c8b54 PM |
89 | cmpwi r13, 0 |
90 | bne 1f | |
91 | 2: mtcr r12 | |
92 | mfspr r12, SPRN_SPRG_SCRATCH1 | |
93 | mfspr r13, SPRN_SPRG_SCRATCH0 /* r13 = original r13 */ | |
94 | b kvmppc_resume_\intno /* Get back original handler */ | |
95 | ||
96 | 1: tophys(r13, r13) | |
3c42bf8a | 97 | stw r12, HSTATE_SCRATCH1(r13) |
b01c8b54 | 98 | mfspr r12, SPRN_SPRG_SCRATCH1 |
3c42bf8a PM |
99 | stw r12, HSTATE_SCRATCH0(r13) |
100 | lbz r12, HSTATE_IN_GUEST(r13) | |
b4433a7c | 101 | cmpwi r12, KVM_GUEST_MODE_NONE |
c862125c AG |
102 | bne ..kvmppc_handler_hasmagic_\intno |
103 | /* No KVM guest? Then jump back to the Linux handler! */ | |
3c42bf8a | 104 | lwz r12, HSTATE_SCRATCH1(r13) |
b01c8b54 | 105 | b 2b |
c862125c AG |
106 | |
107 | /* Now we know we're handling a KVM guest */ | |
108 | ..kvmppc_handler_hasmagic_\intno: | |
b4433a7c AG |
109 | |
110 | /* Should we just skip the faulting instruction? */ | |
111 | cmpwi r12, KVM_GUEST_MODE_SKIP | |
112 | beq kvmppc_handler_skip_ins | |
113 | ||
c862125c AG |
114 | /* Let's store which interrupt we're handling */ |
115 | li r12, \intno | |
116 | ||
117 | /* Jump into the SLB exit code that goes to the highmem handler */ | |
118 | b kvmppc_handler_trampoline_exit | |
119 | ||
120 | .endm | |
121 | ||
122 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_SYSTEM_RESET | |
123 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_MACHINE_CHECK | |
124 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_DATA_STORAGE | |
c862125c | 125 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_INST_STORAGE |
c862125c AG |
126 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_EXTERNAL |
127 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_ALIGNMENT | |
128 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_PROGRAM | |
129 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_FP_UNAVAIL | |
130 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_DECREMENTER | |
131 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_SYSCALL | |
132 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_TRACE | |
133 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_PERFMON | |
134 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_ALTIVEC | |
8c3a4e0b | 135 | |
b4433a7c AG |
136 | /* |
137 | * Bring us back to the faulting code, but skip the | |
138 | * faulting instruction. | |
139 | * | |
140 | * This is a generic exit path from the interrupt | |
141 | * trampolines above. | |
142 | * | |
143 | * Input Registers: | |
144 | * | |
8c3a4e0b AG |
145 | * R12 = free |
146 | * R13 = Shadow VCPU (PACA) | |
3c42bf8a PM |
147 | * HSTATE.SCRATCH0 = guest R12 |
148 | * HSTATE.SCRATCH1 = guest CR | |
8c3a4e0b | 149 | * SPRG_SCRATCH0 = guest R13 |
b4433a7c AG |
150 | * |
151 | */ | |
152 | kvmppc_handler_skip_ins: | |
153 | ||
154 | /* Patch the IP to the next instruction */ | |
155 | mfsrr0 r12 | |
156 | addi r12, r12, 4 | |
157 | mtsrr0 r12 | |
158 | ||
159 | /* Clean up all state */ | |
3c42bf8a | 160 | lwz r12, HSTATE_SCRATCH1(r13) |
b4433a7c | 161 | mtcr r12 |
3c42bf8a | 162 | PPC_LL r12, HSTATE_SCRATCH0(r13) |
673b189a | 163 | GET_SCRATCH0(r13) |
b4433a7c AG |
164 | |
165 | /* And get back into the code */ | |
166 | RFI | |
b01c8b54 | 167 | #endif |
b4433a7c | 168 | |
c862125c | 169 | /* |
02143947 | 170 | * Call kvmppc_handler_trampoline_enter in real mode |
c862125c | 171 | * |
02143947 | 172 | * On entry, r4 contains the guest shadow MSR |
bd2be683 | 173 | * MSR.EE has to be 0 when calling this function |
c862125c | 174 | */ |
02143947 PM |
175 | _GLOBAL(kvmppc_entry_trampoline) |
176 | mfmsr r5 | |
177 | LOAD_REG_ADDR(r7, kvmppc_handler_trampoline_enter) | |
178 | toreal(r7) | |
179 | ||
02143947 | 180 | li r6, MSR_IR | MSR_DR |
bd2be683 AG |
181 | andc r6, r5, r6 /* Clear DR and IR in MSR value */ |
182 | /* | |
183 | * Set EE in HOST_MSR so that it's enabled when we get into our | |
184 | * C exit handler function | |
185 | */ | |
186 | ori r5, r5, MSR_EE | |
187 | mtsrr0 r7 | |
7e57cba0 | 188 | mtsrr1 r6 |
021ec9c6 AG |
189 | RFI |
190 | ||
8c3a4e0b AG |
191 | #if defined(CONFIG_PPC_BOOK3S_32) |
192 | #define STACK_LR INT_FRAME_SIZE+4 | |
0e677903 AG |
193 | |
194 | /* load_up_xxx have to run with MSR_DR=0 on Book3S_32 */ | |
195 | #define MSR_EXT_START \ | |
196 | PPC_STL r20, _NIP(r1); \ | |
197 | mfmsr r20; \ | |
198 | LOAD_REG_IMMEDIATE(r3, MSR_DR|MSR_EE); \ | |
199 | andc r3,r20,r3; /* Disable DR,EE */ \ | |
200 | mtmsr r3; \ | |
201 | sync | |
202 | ||
203 | #define MSR_EXT_END \ | |
204 | mtmsr r20; /* Enable DR,EE */ \ | |
205 | sync; \ | |
206 | PPC_LL r20, _NIP(r1) | |
207 | ||
8c3a4e0b AG |
208 | #elif defined(CONFIG_PPC_BOOK3S_64) |
209 | #define STACK_LR _LINK | |
0e677903 AG |
210 | #define MSR_EXT_START |
211 | #define MSR_EXT_END | |
8c3a4e0b AG |
212 | #endif |
213 | ||
d5e52813 AG |
214 | /* |
215 | * Activate current's external feature (FPU/Altivec/VSX) | |
216 | */ | |
8c3a4e0b AG |
217 | #define define_load_up(what) \ |
218 | \ | |
219 | _GLOBAL(kvmppc_load_up_ ## what); \ | |
220 | PPC_STLU r1, -INT_FRAME_SIZE(r1); \ | |
221 | mflr r3; \ | |
222 | PPC_STL r3, STACK_LR(r1); \ | |
0e677903 | 223 | MSR_EXT_START; \ |
8c3a4e0b AG |
224 | \ |
225 | bl FUNC(load_up_ ## what); \ | |
226 | \ | |
0e677903 | 227 | MSR_EXT_END; \ |
8c3a4e0b | 228 | PPC_LL r3, STACK_LR(r1); \ |
8c3a4e0b AG |
229 | mtlr r3; \ |
230 | addi r1, r1, INT_FRAME_SIZE; \ | |
d5e52813 AG |
231 | blr |
232 | ||
233 | define_load_up(fpu) | |
234 | #ifdef CONFIG_ALTIVEC | |
235 | define_load_up(altivec) | |
236 | #endif | |
d5e52813 | 237 | |
53e5b8bb | 238 | #include "book3s_segment.S" |