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 | ||
b01c8b54 | 41 | #elif defined(CONFIG_PPC_BOOK3S_32) |
8c3a4e0b | 42 | |
8c3a4e0b AG |
43 | #define FUNC(name) name |
44 | ||
c862125c AG |
45 | .macro INTERRUPT_TRAMPOLINE intno |
46 | ||
47 | .global kvmppc_trampoline_\intno | |
48 | kvmppc_trampoline_\intno: | |
49 | ||
b01c8b54 | 50 | mtspr SPRN_SPRG_SCRATCH0, r13 /* Save r13 */ |
c862125c AG |
51 | |
52 | /* | |
53 | * First thing to do is to find out if we're coming | |
54 | * from a KVM guest or a Linux process. | |
55 | * | |
8c3a4e0b | 56 | * To distinguish, we check a magic byte in the PACA/current |
c862125c | 57 | */ |
b01c8b54 PM |
58 | mfspr r13, SPRN_SPRG_THREAD |
59 | lwz r13, THREAD_KVM_SVCPU(r13) | |
60 | /* PPC32 can have a NULL pointer - let's check for that */ | |
61 | mtspr SPRN_SPRG_SCRATCH1, r12 /* Save r12 */ | |
c862125c | 62 | mfcr r12 |
b01c8b54 PM |
63 | cmpwi r13, 0 |
64 | bne 1f | |
65 | 2: mtcr r12 | |
66 | mfspr r12, SPRN_SPRG_SCRATCH1 | |
67 | mfspr r13, SPRN_SPRG_SCRATCH0 /* r13 = original r13 */ | |
68 | b kvmppc_resume_\intno /* Get back original handler */ | |
69 | ||
70 | 1: tophys(r13, r13) | |
3c42bf8a | 71 | stw r12, HSTATE_SCRATCH1(r13) |
b01c8b54 | 72 | mfspr r12, SPRN_SPRG_SCRATCH1 |
3c42bf8a PM |
73 | stw r12, HSTATE_SCRATCH0(r13) |
74 | lbz r12, HSTATE_IN_GUEST(r13) | |
b4433a7c | 75 | cmpwi r12, KVM_GUEST_MODE_NONE |
c862125c AG |
76 | bne ..kvmppc_handler_hasmagic_\intno |
77 | /* No KVM guest? Then jump back to the Linux handler! */ | |
3c42bf8a | 78 | lwz r12, HSTATE_SCRATCH1(r13) |
b01c8b54 | 79 | b 2b |
c862125c AG |
80 | |
81 | /* Now we know we're handling a KVM guest */ | |
82 | ..kvmppc_handler_hasmagic_\intno: | |
b4433a7c AG |
83 | |
84 | /* Should we just skip the faulting instruction? */ | |
85 | cmpwi r12, KVM_GUEST_MODE_SKIP | |
86 | beq kvmppc_handler_skip_ins | |
87 | ||
c862125c AG |
88 | /* Let's store which interrupt we're handling */ |
89 | li r12, \intno | |
90 | ||
91 | /* Jump into the SLB exit code that goes to the highmem handler */ | |
92 | b kvmppc_handler_trampoline_exit | |
93 | ||
94 | .endm | |
95 | ||
96 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_SYSTEM_RESET | |
97 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_MACHINE_CHECK | |
98 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_DATA_STORAGE | |
c862125c | 99 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_INST_STORAGE |
c862125c AG |
100 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_EXTERNAL |
101 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_ALIGNMENT | |
102 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_PROGRAM | |
103 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_FP_UNAVAIL | |
104 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_DECREMENTER | |
105 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_SYSCALL | |
106 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_TRACE | |
107 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_PERFMON | |
108 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_ALTIVEC | |
8c3a4e0b | 109 | |
b4433a7c AG |
110 | /* |
111 | * Bring us back to the faulting code, but skip the | |
112 | * faulting instruction. | |
113 | * | |
114 | * This is a generic exit path from the interrupt | |
115 | * trampolines above. | |
116 | * | |
117 | * Input Registers: | |
118 | * | |
8c3a4e0b AG |
119 | * R12 = free |
120 | * R13 = Shadow VCPU (PACA) | |
3c42bf8a PM |
121 | * HSTATE.SCRATCH0 = guest R12 |
122 | * HSTATE.SCRATCH1 = guest CR | |
8c3a4e0b | 123 | * SPRG_SCRATCH0 = guest R13 |
b4433a7c AG |
124 | * |
125 | */ | |
126 | kvmppc_handler_skip_ins: | |
127 | ||
128 | /* Patch the IP to the next instruction */ | |
129 | mfsrr0 r12 | |
130 | addi r12, r12, 4 | |
131 | mtsrr0 r12 | |
132 | ||
133 | /* Clean up all state */ | |
3c42bf8a | 134 | lwz r12, HSTATE_SCRATCH1(r13) |
b4433a7c | 135 | mtcr r12 |
3c42bf8a | 136 | PPC_LL r12, HSTATE_SCRATCH0(r13) |
673b189a | 137 | GET_SCRATCH0(r13) |
b4433a7c AG |
138 | |
139 | /* And get back into the code */ | |
140 | RFI | |
b01c8b54 | 141 | #endif |
b4433a7c | 142 | |
c862125c | 143 | /* |
02143947 | 144 | * Call kvmppc_handler_trampoline_enter in real mode |
c862125c | 145 | * |
02143947 | 146 | * On entry, r4 contains the guest shadow MSR |
bd2be683 | 147 | * MSR.EE has to be 0 when calling this function |
c862125c | 148 | */ |
02143947 PM |
149 | _GLOBAL(kvmppc_entry_trampoline) |
150 | mfmsr r5 | |
151 | LOAD_REG_ADDR(r7, kvmppc_handler_trampoline_enter) | |
152 | toreal(r7) | |
153 | ||
02143947 | 154 | li r6, MSR_IR | MSR_DR |
bd2be683 AG |
155 | andc r6, r5, r6 /* Clear DR and IR in MSR value */ |
156 | /* | |
157 | * Set EE in HOST_MSR so that it's enabled when we get into our | |
3d3319b4 | 158 | * C exit handler function. |
bd2be683 AG |
159 | */ |
160 | ori r5, r5, MSR_EE | |
161 | mtsrr0 r7 | |
7e57cba0 | 162 | mtsrr1 r6 |
021ec9c6 AG |
163 | RFI |
164 | ||
8c3a4e0b AG |
165 | #if defined(CONFIG_PPC_BOOK3S_32) |
166 | #define STACK_LR INT_FRAME_SIZE+4 | |
0e677903 AG |
167 | |
168 | /* load_up_xxx have to run with MSR_DR=0 on Book3S_32 */ | |
169 | #define MSR_EXT_START \ | |
170 | PPC_STL r20, _NIP(r1); \ | |
171 | mfmsr r20; \ | |
172 | LOAD_REG_IMMEDIATE(r3, MSR_DR|MSR_EE); \ | |
173 | andc r3,r20,r3; /* Disable DR,EE */ \ | |
174 | mtmsr r3; \ | |
175 | sync | |
176 | ||
177 | #define MSR_EXT_END \ | |
178 | mtmsr r20; /* Enable DR,EE */ \ | |
179 | sync; \ | |
180 | PPC_LL r20, _NIP(r1) | |
181 | ||
8c3a4e0b AG |
182 | #elif defined(CONFIG_PPC_BOOK3S_64) |
183 | #define STACK_LR _LINK | |
0e677903 AG |
184 | #define MSR_EXT_START |
185 | #define MSR_EXT_END | |
8c3a4e0b AG |
186 | #endif |
187 | ||
d5e52813 AG |
188 | /* |
189 | * Activate current's external feature (FPU/Altivec/VSX) | |
190 | */ | |
8c3a4e0b AG |
191 | #define define_load_up(what) \ |
192 | \ | |
193 | _GLOBAL(kvmppc_load_up_ ## what); \ | |
194 | PPC_STLU r1, -INT_FRAME_SIZE(r1); \ | |
195 | mflr r3; \ | |
196 | PPC_STL r3, STACK_LR(r1); \ | |
0e677903 | 197 | MSR_EXT_START; \ |
8c3a4e0b AG |
198 | \ |
199 | bl FUNC(load_up_ ## what); \ | |
200 | \ | |
0e677903 | 201 | MSR_EXT_END; \ |
8c3a4e0b | 202 | PPC_LL r3, STACK_LR(r1); \ |
8c3a4e0b AG |
203 | mtlr r3; \ |
204 | addi r1, r1, INT_FRAME_SIZE; \ | |
d5e52813 AG |
205 | blr |
206 | ||
207 | define_load_up(fpu) | |
208 | #ifdef CONFIG_ALTIVEC | |
209 | define_load_up(altivec) | |
210 | #endif | |
d5e52813 | 211 | |
53e5b8bb | 212 | #include "book3s_segment.S" |