~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/powerpc/kvm/book3s_64_entry.S

Version: ~ [ linux-6.12-rc7 ] ~ [ linux-6.11.7 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.60 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.116 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.171 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.229 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.285 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.323 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.12 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /* SPDX-License-Identifier: GPL-2.0-only */
  2 #include <linux/export.h>
  3 #include <asm/asm-offsets.h>
  4 #include <asm/cache.h>
  5 #include <asm/code-patching-asm.h>
  6 #include <asm/exception-64s.h>
  7 #include <asm/kvm_asm.h>
  8 #include <asm/kvm_book3s_asm.h>
  9 #include <asm/mmu.h>
 10 #include <asm/ppc_asm.h>
 11 #include <asm/ptrace.h>
 12 #include <asm/reg.h>
 13 #include <asm/ultravisor-api.h>
 14 
 15 /*
 16  * These are branched to from interrupt handlers in exception-64s.S which set
 17  * IKVM_REAL or IKVM_VIRT, if HSTATE_IN_GUEST was found to be non-zero.
 18  */
 19 
 20 /*
 21  * This is a hcall, so register convention is as
 22  * Documentation/arch/powerpc/papr_hcalls.rst.
 23  *
 24  * This may also be a syscall from PR-KVM userspace that is to be
 25  * reflected to the PR guest kernel, so registers may be set up for
 26  * a system call rather than hcall. We don't currently clobber
 27  * anything here, but the 0xc00 handler has already clobbered CTR
 28  * and CR0, so PR-KVM can not support a guest kernel that preserves
 29  * those registers across its system calls.
 30  *
 31  * The state of registers is as kvmppc_interrupt, except CFAR is not
 32  * saved, R13 is not in SCRATCH0, and R10 does not contain the trap.
 33  */
 34 .global kvmppc_hcall
 35 .balign IFETCH_ALIGN_BYTES
 36 kvmppc_hcall:
 37 #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
 38         lbz     r10,HSTATE_IN_GUEST(r13)
 39         cmpwi   r10,KVM_GUEST_MODE_HV_P9
 40         beq     kvmppc_p9_exit_hcall
 41 #endif
 42         ld      r10,PACA_EXGEN+EX_R13(r13)
 43         SET_SCRATCH0(r10)
 44         li      r10,0xc00
 45         /* Now we look like kvmppc_interrupt */
 46         li      r11,PACA_EXGEN
 47         b       .Lgot_save_area
 48 
 49 /*
 50  * KVM interrupt entry occurs after GEN_INT_ENTRY runs, and follows that
 51  * call convention:
 52  *
 53  * guest R9-R13, CTR, CFAR, PPR saved in PACA EX_xxx save area
 54  * guest (H)DAR, (H)DSISR are also in the save area for relevant interrupts
 55  * guest R13 also saved in SCRATCH0
 56  * R13          = PACA
 57  * R11          = (H)SRR0
 58  * R12          = (H)SRR1
 59  * R9           = guest CR
 60  * PPR is set to medium
 61  *
 62  * With the addition for KVM:
 63  * R10          = trap vector
 64  */
 65 .global kvmppc_interrupt
 66 .balign IFETCH_ALIGN_BYTES
 67 kvmppc_interrupt:
 68 #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
 69         std     r10,HSTATE_SCRATCH0(r13)
 70         lbz     r10,HSTATE_IN_GUEST(r13)
 71         cmpwi   r10,KVM_GUEST_MODE_HV_P9
 72         beq     kvmppc_p9_exit_interrupt
 73         ld      r10,HSTATE_SCRATCH0(r13)
 74 #endif
 75         li      r11,PACA_EXGEN
 76         cmpdi   r10,0x200
 77         bgt+    .Lgot_save_area
 78         li      r11,PACA_EXMC
 79         beq     .Lgot_save_area
 80         li      r11,PACA_EXNMI
 81 .Lgot_save_area:
 82         add     r11,r11,r13
 83 BEGIN_FTR_SECTION
 84         ld      r12,EX_CFAR(r11)
 85         std     r12,HSTATE_CFAR(r13)
 86 END_FTR_SECTION_IFSET(CPU_FTR_CFAR)
 87         ld      r12,EX_CTR(r11)
 88         mtctr   r12
 89 BEGIN_FTR_SECTION
 90         ld      r12,EX_PPR(r11)
 91         std     r12,HSTATE_PPR(r13)
 92 END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
 93         ld      r12,EX_R12(r11)
 94         std     r12,HSTATE_SCRATCH0(r13)
 95         sldi    r12,r9,32
 96         or      r12,r12,r10
 97         ld      r9,EX_R9(r11)
 98         ld      r10,EX_R10(r11)
 99         ld      r11,EX_R11(r11)
100 
101         /*
102          * Hcalls and other interrupts come here after normalising register
103          * contents and save locations:
104          *
105          * R12          = (guest CR << 32) | interrupt vector
106          * R13          = PACA
107          * guest R12 saved in shadow HSTATE_SCRATCH0
108          * guest R13 saved in SPRN_SCRATCH0
109          */
110         std     r9,HSTATE_SCRATCH2(r13)
111         lbz     r9,HSTATE_IN_GUEST(r13)
112         cmpwi   r9,KVM_GUEST_MODE_SKIP
113         beq-    .Lmaybe_skip
114 .Lno_skip:
115 #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
116 #ifdef CONFIG_KVM_BOOK3S_PR_POSSIBLE
117         cmpwi   r9,KVM_GUEST_MODE_GUEST
118         beq     kvmppc_interrupt_pr
119 #endif
120         b       kvmppc_interrupt_hv
121 #else
122         b       kvmppc_interrupt_pr
123 #endif
124 
125 /*
126  * "Skip" interrupts are part of a trick KVM uses a with hash guests to load
127  * the faulting instruction in guest memory from the hypervisor without
128  * walking page tables.
129  *
130  * When the guest takes a fault that requires the hypervisor to load the
131  * instruction (e.g., MMIO emulation), KVM is running in real-mode with HV=1
132  * and the guest MMU context loaded. It sets KVM_GUEST_MODE_SKIP, and sets
133  * MSR[DR]=1 while leaving MSR[IR]=0, so it continues to fetch HV instructions
134  * but loads and stores will access the guest context. This is used to load
135  * the faulting instruction using the faulting guest effective address.
136  *
137  * However the guest context may not be able to translate, or it may cause a
138  * machine check or other issue, which results in a fault in the host
139  * (even with KVM-HV).
140  *
141  * These faults come here because KVM_GUEST_MODE_SKIP was set, so if they
142  * are (or are likely) caused by that load, the instruction is skipped by
143  * just returning with the PC advanced +4, where it is noticed the load did
144  * not execute and it goes to the slow path which walks the page tables to
145  * read guest memory.
146  */
147 .Lmaybe_skip:
148         cmpwi   r12,BOOK3S_INTERRUPT_MACHINE_CHECK
149         beq     1f
150         cmpwi   r12,BOOK3S_INTERRUPT_DATA_STORAGE
151         beq     1f
152         cmpwi   r12,BOOK3S_INTERRUPT_DATA_SEGMENT
153         beq     1f
154 #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
155         /* HSRR interrupts get 2 added to interrupt number */
156         cmpwi   r12,BOOK3S_INTERRUPT_H_DATA_STORAGE | 0x2
157         beq     2f
158 #endif
159         b       .Lno_skip
160 1:      mfspr   r9,SPRN_SRR0
161         addi    r9,r9,4
162         mtspr   SPRN_SRR0,r9
163         ld      r12,HSTATE_SCRATCH0(r13)
164         ld      r9,HSTATE_SCRATCH2(r13)
165         GET_SCRATCH0(r13)
166         RFI_TO_KERNEL
167 #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
168 2:      mfspr   r9,SPRN_HSRR0
169         addi    r9,r9,4
170         mtspr   SPRN_HSRR0,r9
171         ld      r12,HSTATE_SCRATCH0(r13)
172         ld      r9,HSTATE_SCRATCH2(r13)
173         GET_SCRATCH0(r13)
174         HRFI_TO_KERNEL
175 #endif
176 
177 #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
178 
179 /* Stack frame offsets for kvmppc_p9_enter_guest */
180 #define SFS                     (144 + STACK_FRAME_MIN_SIZE)
181 #define STACK_SLOT_NVGPRS       (SFS - 144)     /* 18 gprs */
182 
183 /*
184  * void kvmppc_p9_enter_guest(struct vcpu *vcpu);
185  *
186  * Enter the guest on a ISAv3.0 or later system.
187  */
188 .balign IFETCH_ALIGN_BYTES
189 _GLOBAL(kvmppc_p9_enter_guest)
190 EXPORT_SYMBOL_GPL(kvmppc_p9_enter_guest)
191         mflr    r0
192         std     r0,PPC_LR_STKOFF(r1)
193         stdu    r1,-SFS(r1)
194 
195         std     r1,HSTATE_HOST_R1(r13)
196 
197         mfcr    r4
198         stw     r4,SFS+8(r1)
199 
200         reg = 14
201         .rept   18
202         std     reg,STACK_SLOT_NVGPRS + ((reg - 14) * 8)(r1)
203         reg = reg + 1
204         .endr
205 
206         ld      r4,VCPU_LR(r3)
207         mtlr    r4
208         ld      r4,VCPU_CTR(r3)
209         mtctr   r4
210         ld      r4,VCPU_XER(r3)
211         mtspr   SPRN_XER,r4
212 
213         ld      r1,VCPU_CR(r3)
214 
215 BEGIN_FTR_SECTION
216         ld      r4,VCPU_CFAR(r3)
217         mtspr   SPRN_CFAR,r4
218 END_FTR_SECTION_IFSET(CPU_FTR_CFAR)
219 BEGIN_FTR_SECTION
220         ld      r4,VCPU_PPR(r3)
221         mtspr   SPRN_PPR,r4
222 END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
223 
224         reg = 4
225         .rept   28
226         ld      reg,__VCPU_GPR(reg)(r3)
227         reg = reg + 1
228         .endr
229 
230         ld      r4,VCPU_KVM(r3)
231         lbz     r4,KVM_SECURE_GUEST(r4)
232         cmpdi   r4,0
233         ld      r4,VCPU_GPR(R4)(r3)
234         bne     .Lret_to_ultra
235 
236         mtcr    r1
237 
238         ld      r0,VCPU_GPR(R0)(r3)
239         ld      r1,VCPU_GPR(R1)(r3)
240         ld      r2,VCPU_GPR(R2)(r3)
241         ld      r3,VCPU_GPR(R3)(r3)
242 
243         HRFI_TO_GUEST
244         b       .
245 
246         /*
247          * Use UV_RETURN ultracall to return control back to the Ultravisor
248          * after processing an hypercall or interrupt that was forwarded
249          * (a.k.a. reflected) to the Hypervisor.
250          *
251          * All registers have already been reloaded except the ucall requires:
252          *   R0 = hcall result
253          *   R2 = SRR1, so UV can detect a synthesized interrupt (if any)
254          *   R3 = UV_RETURN
255          */
256 .Lret_to_ultra:
257         mtcr    r1
258         ld      r1,VCPU_GPR(R1)(r3)
259 
260         ld      r0,VCPU_GPR(R3)(r3)
261         mfspr   r2,SPRN_SRR1
262         LOAD_REG_IMMEDIATE(r3, UV_RETURN)
263         sc      2
264 
265 /*
266  * kvmppc_p9_exit_hcall and kvmppc_p9_exit_interrupt are branched to from
267  * above if the interrupt was taken for a guest that was entered via
268  * kvmppc_p9_enter_guest().
269  *
270  * The exit code recovers the host stack and vcpu pointer, saves all guest GPRs
271  * and CR, LR, XER as well as guest MSR and NIA into the VCPU, then re-
272  * establishes the host stack and registers to return from the
273  * kvmppc_p9_enter_guest() function, which saves CTR and other guest registers
274  * (SPRs and FP, VEC, etc).
275  */
276 .balign IFETCH_ALIGN_BYTES
277 kvmppc_p9_exit_hcall:
278         mfspr   r11,SPRN_SRR0
279         mfspr   r12,SPRN_SRR1
280         li      r10,0xc00
281         std     r10,HSTATE_SCRATCH0(r13)
282 
283 .balign IFETCH_ALIGN_BYTES
284 kvmppc_p9_exit_interrupt:
285         /*
286          * If set to KVM_GUEST_MODE_HV_P9 but we're still in the
287          * hypervisor, that means we can't return from the entry stack.
288          */
289         rldicl. r10,r12,64-MSR_HV_LG,63
290         bne-    kvmppc_p9_bad_interrupt
291 
292         std     r1,HSTATE_SCRATCH1(r13)
293         std     r3,HSTATE_SCRATCH2(r13)
294         ld      r1,HSTATE_HOST_R1(r13)
295         ld      r3,HSTATE_KVM_VCPU(r13)
296 
297         std     r9,VCPU_CR(r3)
298 
299 1:
300         std     r11,VCPU_PC(r3)
301         std     r12,VCPU_MSR(r3)
302 
303         reg = 14
304         .rept   18
305         std     reg,__VCPU_GPR(reg)(r3)
306         reg = reg + 1
307         .endr
308 
309         /* r1, r3, r9-r13 are saved to vcpu by C code */
310         std     r0,VCPU_GPR(R0)(r3)
311         std     r2,VCPU_GPR(R2)(r3)
312         reg = 4
313         .rept   5
314         std     reg,__VCPU_GPR(reg)(r3)
315         reg = reg + 1
316         .endr
317 
318         LOAD_PACA_TOC()
319 
320         mflr    r4
321         std     r4,VCPU_LR(r3)
322         mfspr   r4,SPRN_XER
323         std     r4,VCPU_XER(r3)
324 
325         reg = 14
326         .rept   18
327         ld      reg,STACK_SLOT_NVGPRS + ((reg - 14) * 8)(r1)
328         reg = reg + 1
329         .endr
330 
331         lwz     r4,SFS+8(r1)
332         mtcr    r4
333 
334         /*
335          * Flush the link stack here, before executing the first blr on the
336          * way out of the guest.
337          *
338          * The link stack won't match coming out of the guest anyway so the
339          * only cost is the flush itself. The call clobbers r0.
340          */
341 1:      nop
342         patch_site 1b patch__call_kvm_flush_link_stack_p9
343 
344         addi    r1,r1,SFS
345         ld      r0,PPC_LR_STKOFF(r1)
346         mtlr    r0
347         blr
348 
349 /*
350  * Took an interrupt somewhere right before HRFID to guest, so registers are
351  * in a bad way. Return things hopefully enough to run host virtual code and
352  * run the Linux interrupt handler (SRESET or MCE) to print something useful.
353  *
354  * We could be really clever and save all host registers in known locations
355  * before setting HSTATE_IN_GUEST, then restoring them all here, and setting
356  * return address to a fixup that sets them up again. But that's a lot of
357  * effort for a small bit of code. Lots of other things to do first.
358  */
359 kvmppc_p9_bad_interrupt:
360 BEGIN_MMU_FTR_SECTION
361         /*
362          * Hash host doesn't try to recover MMU (requires host SLB reload)
363          */
364         b       .
365 END_MMU_FTR_SECTION_IFCLR(MMU_FTR_TYPE_RADIX)
366         /*
367          * Clean up guest registers to give host a chance to run.
368          */
369         li      r10,0
370         mtspr   SPRN_AMR,r10
371         mtspr   SPRN_IAMR,r10
372         mtspr   SPRN_CIABR,r10
373         mtspr   SPRN_DAWRX0,r10
374 BEGIN_FTR_SECTION
375         mtspr   SPRN_DAWRX1,r10
376 END_FTR_SECTION_IFSET(CPU_FTR_DAWR1)
377 
378         /*
379          * Switch to host MMU mode (don't have the real host PID but we aren't
380          * going back to userspace).
381          */
382         hwsync
383         isync
384 
385         mtspr   SPRN_PID,r10
386 
387         ld      r10, HSTATE_KVM_VCPU(r13)
388         ld      r10, VCPU_KVM(r10)
389         lwz     r10, KVM_HOST_LPID(r10)
390         mtspr   SPRN_LPID,r10
391 
392         ld      r10, HSTATE_KVM_VCPU(r13)
393         ld      r10, VCPU_KVM(r10)
394         ld      r10, KVM_HOST_LPCR(r10)
395         mtspr   SPRN_LPCR,r10
396 
397         isync
398 
399         /*
400          * Set GUEST_MODE_NONE so the handler won't branch to KVM, and clear
401          * MSR_RI in r12 ([H]SRR1) so the handler won't try to return.
402          */
403         li      r10,KVM_GUEST_MODE_NONE
404         stb     r10,HSTATE_IN_GUEST(r13)
405         li      r10,MSR_RI
406         andc    r12,r12,r10
407 
408         /*
409          * Go back to interrupt handler. MCE and SRESET have their specific
410          * PACA save area so they should be used directly. They set up their
411          * own stack. The other handlers all use EXGEN. They will use the
412          * guest r1 if it looks like a kernel stack, so just load the
413          * emergency stack and go to program check for all other interrupts.
414          */
415         ld      r10,HSTATE_SCRATCH0(r13)
416         cmpwi   r10,BOOK3S_INTERRUPT_MACHINE_CHECK
417         beq     .Lcall_machine_check_common
418 
419         cmpwi   r10,BOOK3S_INTERRUPT_SYSTEM_RESET
420         beq     .Lcall_system_reset_common
421 
422         b       .
423 
424 .Lcall_machine_check_common:
425         b       machine_check_common
426 
427 .Lcall_system_reset_common:
428         b       system_reset_common
429 #endif

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php