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#define SHADOW_SLB_ESID(num) (SLBSHADOW_SAVEAREA + (num * 0x10)) 21#define SHADOW_SLB_VSID(num) (SLBSHADOW_SAVEAREA + (num * 0x10) + 0x8) 22#define UNBOLT_SLB_ENTRY(num) \ 23 ld r9, SHADOW_SLB_ESID(num)(r12); \ 24 /* Invalid? Skip. */; \ 25 rldicl. r0, r9, 37, 63; \ 26 beq slb_entry_skip_ ## num; \ 27 xoris r9, r9, SLB_ESID_V@h; \ 28 std r9, SHADOW_SLB_ESID(num)(r12); \ 29 slb_entry_skip_ ## num: 30 31#define REBOLT_SLB_ENTRY(num) \ 32 ld r10, SHADOW_SLB_ESID(num)(r11); \ 33 cmpdi r10, 0; \ 34 beq slb_exit_skip_ ## num; \ 35 oris r10, r10, SLB_ESID_V@h; \ 36 ld r9, SHADOW_SLB_VSID(num)(r11); \ 37 slbmte r9, r10; \ 38 std r10, SHADOW_SLB_ESID(num)(r11); \ 39slb_exit_skip_ ## num: 40 41/****************************************************************************** 42 * * 43 * Entry code * 44 * * 45 *****************************************************************************/ 46 47.global kvmppc_handler_trampoline_enter 48kvmppc_handler_trampoline_enter: 49 50 /* Required state: 51 * 52 * MSR = ~IR|DR 53 * R13 = PACA 54 * R1 = host R1 55 * R2 = host R2 56 * R9 = guest IP 57 * R10 = guest MSR 58 * all other GPRS = free 59 * PACA[KVM_CR] = guest CR 60 * PACA[KVM_XER] = guest XER 61 */ 62 63 mtsrr0 r9 64 mtsrr1 r10 65 66 /* Activate guest mode, so faults get handled by KVM */ 67 li r11, KVM_GUEST_MODE_GUEST 68 stb r11, PACA_KVM_IN_GUEST(r13) 69 70 /* Remove LPAR shadow entries */ 71 72#if SLB_NUM_BOLTED == 3 73 74 ld r12, PACA_SLBSHADOWPTR(r13) 75 76 /* Save off the first entry so we can slbie it later */ 77 ld r10, SHADOW_SLB_ESID(0)(r12) 78 ld r11, SHADOW_SLB_VSID(0)(r12) 79 80 /* Remove bolted entries */ 81 UNBOLT_SLB_ENTRY(0) 82 UNBOLT_SLB_ENTRY(1) 83 UNBOLT_SLB_ENTRY(2) 84 85#else 86#error unknown number of bolted entries 87#endif 88 89 /* Flush SLB */ 90 91 slbia 92 93 /* r0 = esid & ESID_MASK */ 94 rldicr r10, r10, 0, 35 95 /* r0 |= CLASS_BIT(VSID) */ 96 rldic r12, r11, 56 - 36, 36 97 or r10, r10, r12 98 slbie r10 99 100 isync 101 102 /* Fill SLB with our shadow */ 103 104 lbz r12, PACA_KVM_SLB_MAX(r13) 105 mulli r12, r12, 16 106 addi r12, r12, PACA_KVM_SLB 107 add r12, r12, r13 108 109 /* for (r11 = kvm_slb; r11 < kvm_slb + kvm_slb_size; r11+=slb_entry) */ 110 li r11, PACA_KVM_SLB 111 add r11, r11, r13 112 113slb_loop_enter: 114 115 ld r10, 0(r11) 116 117 rldicl. r0, r10, 37, 63 118 beq slb_loop_enter_skip 119 120 ld r9, 8(r11) 121 slbmte r9, r10 122 123slb_loop_enter_skip: 124 addi r11, r11, 16 125 cmpd cr0, r11, r12 126 blt slb_loop_enter 127 128slb_do_enter: 129 130 /* Enter guest */ 131 132 ld r0, (PACA_KVM_R0)(r13) 133 ld r1, (PACA_KVM_R1)(r13) 134 ld r2, (PACA_KVM_R2)(r13) 135 ld r3, (PACA_KVM_R3)(r13) 136 ld r4, (PACA_KVM_R4)(r13) 137 ld r5, (PACA_KVM_R5)(r13) 138 ld r6, (PACA_KVM_R6)(r13) 139 ld r7, (PACA_KVM_R7)(r13) 140 ld r8, (PACA_KVM_R8)(r13) 141 ld r9, (PACA_KVM_R9)(r13) 142 ld r10, (PACA_KVM_R10)(r13) 143 ld r12, (PACA_KVM_R12)(r13) 144 145 lwz r11, (PACA_KVM_CR)(r13) 146 mtcr r11 147 148 ld r11, (PACA_KVM_XER)(r13) 149 mtxer r11 150 151 ld r11, (PACA_KVM_R11)(r13) 152 ld r13, (PACA_KVM_R13)(r13) 153 154 RFI 155kvmppc_handler_trampoline_enter_end: 156 157 158 159/****************************************************************************** 160 * * 161 * Exit code * 162 * * 163 *****************************************************************************/ 164 165.global kvmppc_handler_trampoline_exit 166kvmppc_handler_trampoline_exit: 167 168 /* Register usage at this point: 169 * 170 * SPRG_SCRATCH0 = guest R13 171 * R12 = exit handler id 172 * R13 = PACA 173 * PACA.KVM.SCRATCH0 = guest R12 174 * PACA.KVM.SCRATCH1 = guest CR 175 * 176 */ 177 178 /* Save registers */ 179 180 std r0, PACA_KVM_R0(r13) 181 std r1, PACA_KVM_R1(r13) 182 std r2, PACA_KVM_R2(r13) 183 std r3, PACA_KVM_R3(r13) 184 std r4, PACA_KVM_R4(r13) 185 std r5, PACA_KVM_R5(r13) 186 std r6, PACA_KVM_R6(r13) 187 std r7, PACA_KVM_R7(r13) 188 std r8, PACA_KVM_R8(r13) 189 std r9, PACA_KVM_R9(r13) 190 std r10, PACA_KVM_R10(r13) 191 std r11, PACA_KVM_R11(r13) 192 193 /* Restore R1/R2 so we can handle faults */ 194 ld r1, PACA_KVM_HOST_R1(r13) 195 ld r2, PACA_KVM_HOST_R2(r13) 196 197 /* Save guest PC and MSR in GPRs */ 198 mfsrr0 r3 199 mfsrr1 r4 200 201 /* Get scratch'ed off registers */ 202 mfspr r9, SPRN_SPRG_SCRATCH0 203 std r9, PACA_KVM_R13(r13) 204 205 ld r8, PACA_KVM_SCRATCH0(r13) 206 std r8, PACA_KVM_R12(r13) 207 208 lwz r7, PACA_KVM_SCRATCH1(r13) 209 stw r7, PACA_KVM_CR(r13) 210 211 /* Save more register state */ 212 213 mfxer r6 214 stw r6, PACA_KVM_XER(r13) 215 216 mfdar r5 217 mfdsisr r6 218 219 /* 220 * In order for us to easily get the last instruction, 221 * we got the #vmexit at, we exploit the fact that the 222 * virtual layout is still the same here, so we can just 223 * ld from the guest's PC address 224 */ 225 226 /* We only load the last instruction when it's safe */ 227 cmpwi r12, BOOK3S_INTERRUPT_DATA_STORAGE 228 beq ld_last_inst 229 cmpwi r12, BOOK3S_INTERRUPT_PROGRAM 230 beq ld_last_inst 231 232 b no_ld_last_inst 233 234ld_last_inst: 235 /* Save off the guest instruction we're at */ 236 237 /* Set guest mode to 'jump over instruction' so if lwz faults 238 * we'll just continue at the next IP. */ 239 li r9, KVM_GUEST_MODE_SKIP 240 stb r9, PACA_KVM_IN_GUEST(r13) 241 242 /* 1) enable paging for data */ 243 mfmsr r9 244 ori r11, r9, MSR_DR /* Enable paging for data */ 245 mtmsr r11 246 /* 2) fetch the instruction */ 247 li r0, KVM_INST_FETCH_FAILED /* In case lwz faults */ 248 lwz r0, 0(r3) 249 /* 3) disable paging again */ 250 mtmsr r9 251 252no_ld_last_inst: 253 254 /* Unset guest mode */ 255 li r9, KVM_GUEST_MODE_NONE 256 stb r9, PACA_KVM_IN_GUEST(r13) 257 258 /* Restore bolted entries from the shadow and fix it along the way */ 259 260 /* We don't store anything in entry 0, so we don't need to take care of it */ 261 slbia 262 isync 263 264#if SLB_NUM_BOLTED == 3 265 266 ld r11, PACA_SLBSHADOWPTR(r13) 267 268 REBOLT_SLB_ENTRY(0) 269 REBOLT_SLB_ENTRY(1) 270 REBOLT_SLB_ENTRY(2) 271 272#else 273#error unknown number of bolted entries 274#endif 275 276slb_do_exit: 277 278 /* Register usage at this point: 279 * 280 * R0 = guest last inst 281 * R1 = host R1 282 * R2 = host R2 283 * R3 = guest PC 284 * R4 = guest MSR 285 * R5 = guest DAR 286 * R6 = guest DSISR 287 * R12 = exit handler id 288 * R13 = PACA 289 * PACA.KVM.* = guest * 290 * 291 */ 292 293 /* RFI into the highmem handler */ 294 mfmsr r7 295 ori r7, r7, MSR_IR|MSR_DR|MSR_RI /* Enable paging */ 296 mtsrr1 r7 297 ld r8, PACA_KVM_VMHANDLER(r13) /* Highmem handler address */ 298 mtsrr0 r8 299 300 RFI 301kvmppc_handler_trampoline_exit_end: 302 303