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 | ||
2dd60d79 | 39 | #define LOAD_SHADOW_VCPU(reg) GET_PACA(reg) |
8c3a4e0b AG |
40 | #define MSR_NOIRQ MSR_KERNEL & ~(MSR_IR | MSR_DR) |
41 | #define FUNC(name) GLUE(.,name) | |
42 | ||
177339d7 | 43 | .globl kvmppc_skip_interrupt |
b01c8b54 PM |
44 | kvmppc_skip_interrupt: |
45 | /* | |
46 | * Here all GPRs are unchanged from when the interrupt happened | |
47 | * except for r13, which is saved in SPRG_SCRATCH0. | |
48 | */ | |
49 | mfspr r13, SPRN_SRR0 | |
50 | addi r13, r13, 4 | |
51 | mtspr SPRN_SRR0, r13 | |
52 | GET_SCRATCH0(r13) | |
53 | rfid | |
54 | b . | |
55 | ||
177339d7 | 56 | .globl kvmppc_skip_Hinterrupt |
b01c8b54 PM |
57 | kvmppc_skip_Hinterrupt: |
58 | /* | |
59 | * Here all GPRs are unchanged from when the interrupt happened | |
60 | * except for r13, which is saved in SPRG_SCRATCH0. | |
61 | */ | |
62 | mfspr r13, SPRN_HSRR0 | |
63 | addi r13, r13, 4 | |
64 | mtspr SPRN_HSRR0, r13 | |
65 | GET_SCRATCH0(r13) | |
66 | hrfid | |
67 | b . | |
8c3a4e0b | 68 | |
b01c8b54 | 69 | #elif defined(CONFIG_PPC_BOOK3S_32) |
8c3a4e0b | 70 | |
8c3a4e0b AG |
71 | #define MSR_NOIRQ MSR_KERNEL |
72 | #define FUNC(name) name | |
73 | ||
c862125c AG |
74 | .macro INTERRUPT_TRAMPOLINE intno |
75 | ||
76 | .global kvmppc_trampoline_\intno | |
77 | kvmppc_trampoline_\intno: | |
78 | ||
b01c8b54 | 79 | mtspr SPRN_SPRG_SCRATCH0, r13 /* Save r13 */ |
c862125c AG |
80 | |
81 | /* | |
82 | * First thing to do is to find out if we're coming | |
83 | * from a KVM guest or a Linux process. | |
84 | * | |
8c3a4e0b | 85 | * To distinguish, we check a magic byte in the PACA/current |
c862125c | 86 | */ |
b01c8b54 PM |
87 | mfspr r13, SPRN_SPRG_THREAD |
88 | lwz r13, THREAD_KVM_SVCPU(r13) | |
89 | /* PPC32 can have a NULL pointer - let's check for that */ | |
90 | mtspr SPRN_SPRG_SCRATCH1, r12 /* Save r12 */ | |
c862125c | 91 | mfcr r12 |
b01c8b54 PM |
92 | cmpwi r13, 0 |
93 | bne 1f | |
94 | 2: mtcr r12 | |
95 | mfspr r12, SPRN_SPRG_SCRATCH1 | |
96 | mfspr r13, SPRN_SPRG_SCRATCH0 /* r13 = original r13 */ | |
97 | b kvmppc_resume_\intno /* Get back original handler */ | |
98 | ||
99 | 1: tophys(r13, r13) | |
3c42bf8a | 100 | stw r12, HSTATE_SCRATCH1(r13) |
b01c8b54 | 101 | mfspr r12, SPRN_SPRG_SCRATCH1 |
3c42bf8a PM |
102 | stw r12, HSTATE_SCRATCH0(r13) |
103 | lbz r12, HSTATE_IN_GUEST(r13) | |
b4433a7c | 104 | cmpwi r12, KVM_GUEST_MODE_NONE |
c862125c AG |
105 | bne ..kvmppc_handler_hasmagic_\intno |
106 | /* No KVM guest? Then jump back to the Linux handler! */ | |
3c42bf8a | 107 | lwz r12, HSTATE_SCRATCH1(r13) |
b01c8b54 | 108 | b 2b |
c862125c AG |
109 | |
110 | /* Now we know we're handling a KVM guest */ | |
111 | ..kvmppc_handler_hasmagic_\intno: | |
b4433a7c AG |
112 | |
113 | /* Should we just skip the faulting instruction? */ | |
114 | cmpwi r12, KVM_GUEST_MODE_SKIP | |
115 | beq kvmppc_handler_skip_ins | |
116 | ||
c862125c AG |
117 | /* Let's store which interrupt we're handling */ |
118 | li r12, \intno | |
119 | ||
120 | /* Jump into the SLB exit code that goes to the highmem handler */ | |
121 | b kvmppc_handler_trampoline_exit | |
122 | ||
123 | .endm | |
124 | ||
125 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_SYSTEM_RESET | |
126 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_MACHINE_CHECK | |
127 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_DATA_STORAGE | |
c862125c | 128 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_INST_STORAGE |
c862125c AG |
129 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_EXTERNAL |
130 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_ALIGNMENT | |
131 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_PROGRAM | |
132 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_FP_UNAVAIL | |
133 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_DECREMENTER | |
134 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_SYSCALL | |
135 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_TRACE | |
136 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_PERFMON | |
137 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_ALTIVEC | |
8c3a4e0b | 138 | |
b4433a7c AG |
139 | /* |
140 | * Bring us back to the faulting code, but skip the | |
141 | * faulting instruction. | |
142 | * | |
143 | * This is a generic exit path from the interrupt | |
144 | * trampolines above. | |
145 | * | |
146 | * Input Registers: | |
147 | * | |
8c3a4e0b AG |
148 | * R12 = free |
149 | * R13 = Shadow VCPU (PACA) | |
3c42bf8a PM |
150 | * HSTATE.SCRATCH0 = guest R12 |
151 | * HSTATE.SCRATCH1 = guest CR | |
8c3a4e0b | 152 | * SPRG_SCRATCH0 = guest R13 |
b4433a7c AG |
153 | * |
154 | */ | |
155 | kvmppc_handler_skip_ins: | |
156 | ||
157 | /* Patch the IP to the next instruction */ | |
158 | mfsrr0 r12 | |
159 | addi r12, r12, 4 | |
160 | mtsrr0 r12 | |
161 | ||
162 | /* Clean up all state */ | |
3c42bf8a | 163 | lwz r12, HSTATE_SCRATCH1(r13) |
b4433a7c | 164 | mtcr r12 |
3c42bf8a | 165 | PPC_LL r12, HSTATE_SCRATCH0(r13) |
673b189a | 166 | GET_SCRATCH0(r13) |
b4433a7c AG |
167 | |
168 | /* And get back into the code */ | |
169 | RFI | |
b01c8b54 | 170 | #endif |
b4433a7c | 171 | |
c862125c AG |
172 | /* |
173 | * This trampoline brings us back to a real mode handler | |
174 | * | |
175 | * Input Registers: | |
176 | * | |
7e57cba0 AG |
177 | * R5 = SRR0 |
178 | * R6 = SRR1 | |
c862125c AG |
179 | * LR = real-mode IP |
180 | * | |
181 | */ | |
182 | .global kvmppc_handler_lowmem_trampoline | |
183 | kvmppc_handler_lowmem_trampoline: | |
184 | ||
7e57cba0 AG |
185 | mtsrr0 r5 |
186 | mtsrr1 r6 | |
c862125c AG |
187 | blr |
188 | kvmppc_handler_lowmem_trampoline_end: | |
189 | ||
021ec9c6 AG |
190 | /* |
191 | * Call a function in real mode | |
192 | * | |
193 | * Input Registers: | |
194 | * | |
195 | * R3 = function | |
196 | * R4 = MSR | |
8c3a4e0b | 197 | * R5 = scratch register |
021ec9c6 AG |
198 | * |
199 | */ | |
200 | _GLOBAL(kvmppc_rmcall) | |
8c3a4e0b AG |
201 | LOAD_REG_IMMEDIATE(r5, MSR_NOIRQ) |
202 | mtmsr r5 /* Disable relocation and interrupts, so mtsrr | |
021ec9c6 | 203 | doesn't get interrupted */ |
8c3a4e0b | 204 | sync |
021ec9c6 AG |
205 | mtsrr0 r3 |
206 | mtsrr1 r4 | |
207 | RFI | |
208 | ||
8c3a4e0b AG |
209 | #if defined(CONFIG_PPC_BOOK3S_32) |
210 | #define STACK_LR INT_FRAME_SIZE+4 | |
0e677903 AG |
211 | |
212 | /* load_up_xxx have to run with MSR_DR=0 on Book3S_32 */ | |
213 | #define MSR_EXT_START \ | |
214 | PPC_STL r20, _NIP(r1); \ | |
215 | mfmsr r20; \ | |
216 | LOAD_REG_IMMEDIATE(r3, MSR_DR|MSR_EE); \ | |
217 | andc r3,r20,r3; /* Disable DR,EE */ \ | |
218 | mtmsr r3; \ | |
219 | sync | |
220 | ||
221 | #define MSR_EXT_END \ | |
222 | mtmsr r20; /* Enable DR,EE */ \ | |
223 | sync; \ | |
224 | PPC_LL r20, _NIP(r1) | |
225 | ||
8c3a4e0b AG |
226 | #elif defined(CONFIG_PPC_BOOK3S_64) |
227 | #define STACK_LR _LINK | |
0e677903 AG |
228 | #define MSR_EXT_START |
229 | #define MSR_EXT_END | |
8c3a4e0b AG |
230 | #endif |
231 | ||
d5e52813 AG |
232 | /* |
233 | * Activate current's external feature (FPU/Altivec/VSX) | |
234 | */ | |
8c3a4e0b AG |
235 | #define define_load_up(what) \ |
236 | \ | |
237 | _GLOBAL(kvmppc_load_up_ ## what); \ | |
238 | PPC_STLU r1, -INT_FRAME_SIZE(r1); \ | |
239 | mflr r3; \ | |
240 | PPC_STL r3, STACK_LR(r1); \ | |
0e677903 | 241 | MSR_EXT_START; \ |
8c3a4e0b AG |
242 | \ |
243 | bl FUNC(load_up_ ## what); \ | |
244 | \ | |
0e677903 | 245 | MSR_EXT_END; \ |
8c3a4e0b | 246 | PPC_LL r3, STACK_LR(r1); \ |
8c3a4e0b AG |
247 | mtlr r3; \ |
248 | addi r1, r1, INT_FRAME_SIZE; \ | |
d5e52813 AG |
249 | blr |
250 | ||
251 | define_load_up(fpu) | |
252 | #ifdef CONFIG_ALTIVEC | |
253 | define_load_up(altivec) | |
254 | #endif | |
255 | #ifdef CONFIG_VSX | |
256 | define_load_up(vsx) | |
257 | #endif | |
258 | ||
53e5b8bb | 259 | #include "book3s_segment.S" |