Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0-only */
0002 /*
0003  *
0004  * Copyright SUSE Linux Products GmbH 2009
0005  *
0006  * Authors: Alexander Graf <agraf@suse.de>
0007  */
0008 
0009 #include <asm/ppc_asm.h>
0010 #include <asm/kvm_asm.h>
0011 #include <asm/reg.h>
0012 #include <asm/page.h>
0013 #include <asm/asm-offsets.h>
0014 #include <asm/exception-64s.h>
0015 #include <asm/asm-compat.h>
0016 
0017 #if defined(CONFIG_PPC_BOOK3S_64)
0018 #ifdef CONFIG_PPC64_ELF_ABI_V2
0019 #define FUNC(name)      name
0020 #else
0021 #define FUNC(name)      GLUE(.,name)
0022 #endif
0023 #define GET_SHADOW_VCPU(reg)    addi    reg, r13, PACA_SVCPU
0024 
0025 #elif defined(CONFIG_PPC_BOOK3S_32)
0026 #define FUNC(name)      name
0027 #define GET_SHADOW_VCPU(reg)    lwz     reg, (THREAD + THREAD_KVM_SVCPU)(r2)
0028 
0029 #endif /* CONFIG_PPC_BOOK3S_64 */
0030 
0031 #define VCPU_LOAD_NVGPRS(vcpu) \
0032     PPC_LL  r14, VCPU_GPR(R14)(vcpu); \
0033     PPC_LL  r15, VCPU_GPR(R15)(vcpu); \
0034     PPC_LL  r16, VCPU_GPR(R16)(vcpu); \
0035     PPC_LL  r17, VCPU_GPR(R17)(vcpu); \
0036     PPC_LL  r18, VCPU_GPR(R18)(vcpu); \
0037     PPC_LL  r19, VCPU_GPR(R19)(vcpu); \
0038     PPC_LL  r20, VCPU_GPR(R20)(vcpu); \
0039     PPC_LL  r21, VCPU_GPR(R21)(vcpu); \
0040     PPC_LL  r22, VCPU_GPR(R22)(vcpu); \
0041     PPC_LL  r23, VCPU_GPR(R23)(vcpu); \
0042     PPC_LL  r24, VCPU_GPR(R24)(vcpu); \
0043     PPC_LL  r25, VCPU_GPR(R25)(vcpu); \
0044     PPC_LL  r26, VCPU_GPR(R26)(vcpu); \
0045     PPC_LL  r27, VCPU_GPR(R27)(vcpu); \
0046     PPC_LL  r28, VCPU_GPR(R28)(vcpu); \
0047     PPC_LL  r29, VCPU_GPR(R29)(vcpu); \
0048     PPC_LL  r30, VCPU_GPR(R30)(vcpu); \
0049     PPC_LL  r31, VCPU_GPR(R31)(vcpu); \
0050 
0051 /*****************************************************************************
0052  *                                                                           *
0053  *     Guest entry / exit code that is in kernel module memory (highmem)     *
0054  *                                                                           *
0055  ****************************************************************************/
0056 
0057 /* Registers:
0058  *  r3: vcpu pointer
0059  */
0060 _GLOBAL(__kvmppc_vcpu_run)
0061 
0062 kvm_start_entry:
0063     /* Write correct stack frame */
0064     mflr    r0
0065     PPC_STL r0,PPC_LR_STKOFF(r1)
0066 
0067     /* Save host state to the stack */
0068     PPC_STLU r1, -SWITCH_FRAME_SIZE(r1)
0069 
0070     /* Save r3 (vcpu) */
0071     SAVE_GPR(3, r1)
0072 
0073     /* Save non-volatile registers (r14 - r31) */
0074     SAVE_NVGPRS(r1)
0075 
0076     /* Save CR */
0077     mfcr    r14
0078     stw r14, _CCR(r1)
0079 
0080     /* Save LR */
0081     PPC_STL r0, _LINK(r1)
0082 
0083     /* Load non-volatile guest state from the vcpu */
0084     VCPU_LOAD_NVGPRS(r3)
0085 
0086 kvm_start_lightweight:
0087     /* Copy registers into shadow vcpu so we can access them in real mode */
0088     bl  FUNC(kvmppc_copy_to_svcpu)
0089     nop
0090     REST_GPR(3, r1)
0091 
0092 #ifdef CONFIG_PPC_BOOK3S_64
0093     /* Get the dcbz32 flag */
0094     PPC_LL  r0, VCPU_HFLAGS(r3)
0095     rldicl  r0, r0, 0, 63       /* r3 &= 1 */
0096     stb r0, HSTATE_RESTORE_HID5(r13)
0097 
0098     /* Load up guest SPRG3 value, since it's user readable */
0099     lbz r4, VCPU_SHAREDBE(r3)
0100     cmpwi   r4, 0
0101     ld  r5, VCPU_SHARED(r3)
0102     beq sprg3_little_endian
0103 sprg3_big_endian:
0104 #ifdef __BIG_ENDIAN__
0105     ld  r4, VCPU_SHARED_SPRG3(r5)
0106 #else
0107     addi    r5, r5, VCPU_SHARED_SPRG3
0108     ldbrx   r4, 0, r5
0109 #endif
0110     b   after_sprg3_load
0111 sprg3_little_endian:
0112 #ifdef __LITTLE_ENDIAN__
0113     ld  r4, VCPU_SHARED_SPRG3(r5)
0114 #else
0115     addi    r5, r5, VCPU_SHARED_SPRG3
0116     ldbrx   r4, 0, r5
0117 #endif
0118 
0119 after_sprg3_load:
0120     mtspr   SPRN_SPRG3, r4
0121 #endif /* CONFIG_PPC_BOOK3S_64 */
0122 
0123     PPC_LL  r4, VCPU_SHADOW_MSR(r3) /* get shadow_msr */
0124 
0125     /* Jump to segment patching handler and into our guest */
0126     bl  FUNC(kvmppc_entry_trampoline)
0127     nop
0128 
0129 /*
0130  * This is the handler in module memory. It gets jumped at from the
0131  * lowmem trampoline code, so it's basically the guest exit code.
0132  *
0133  */
0134 
0135     /*
0136      * Register usage at this point:
0137      *
0138      * R1       = host R1
0139      * R2       = host R2
0140      * R12      = exit handler id
0141      * R13      = PACA
0142      * SVCPU.*  = guest *
0143      * MSR.EE   = 1
0144      *
0145      */
0146 
0147     PPC_LL  r3, GPR3(r1)        /* vcpu pointer */
0148 
0149     /*
0150      * kvmppc_copy_from_svcpu can clobber volatile registers, save
0151      * the exit handler id to the vcpu and restore it from there later.
0152      */
0153     stw r12, VCPU_TRAP(r3)
0154 
0155     /* Transfer reg values from shadow vcpu back to vcpu struct */
0156 
0157     bl  FUNC(kvmppc_copy_from_svcpu)
0158     nop
0159 
0160 #ifdef CONFIG_PPC_BOOK3S_64
0161     /*
0162      * Reload kernel SPRG3 value.
0163      * No need to save guest value as usermode can't modify SPRG3.
0164      */
0165     ld  r3, PACA_SPRG_VDSO(r13)
0166     mtspr   SPRN_SPRG_VDSO_WRITE, r3
0167 #endif /* CONFIG_PPC_BOOK3S_64 */
0168 
0169     /* R7 = vcpu */
0170     PPC_LL  r7, GPR3(r1)
0171 
0172     PPC_STL r14, VCPU_GPR(R14)(r7)
0173     PPC_STL r15, VCPU_GPR(R15)(r7)
0174     PPC_STL r16, VCPU_GPR(R16)(r7)
0175     PPC_STL r17, VCPU_GPR(R17)(r7)
0176     PPC_STL r18, VCPU_GPR(R18)(r7)
0177     PPC_STL r19, VCPU_GPR(R19)(r7)
0178     PPC_STL r20, VCPU_GPR(R20)(r7)
0179     PPC_STL r21, VCPU_GPR(R21)(r7)
0180     PPC_STL r22, VCPU_GPR(R22)(r7)
0181     PPC_STL r23, VCPU_GPR(R23)(r7)
0182     PPC_STL r24, VCPU_GPR(R24)(r7)
0183     PPC_STL r25, VCPU_GPR(R25)(r7)
0184     PPC_STL r26, VCPU_GPR(R26)(r7)
0185     PPC_STL r27, VCPU_GPR(R27)(r7)
0186     PPC_STL r28, VCPU_GPR(R28)(r7)
0187     PPC_STL r29, VCPU_GPR(R29)(r7)
0188     PPC_STL r30, VCPU_GPR(R30)(r7)
0189     PPC_STL r31, VCPU_GPR(R31)(r7)
0190 
0191     /* Pass the exit number as 2nd argument to kvmppc_handle_exit */
0192     lwz r4, VCPU_TRAP(r7)
0193 
0194     /* Restore r3 (vcpu) */
0195     REST_GPR(3, r1)
0196     bl  FUNC(kvmppc_handle_exit_pr)
0197 
0198     /* If RESUME_GUEST, get back in the loop */
0199     cmpwi   r3, RESUME_GUEST
0200     beq kvm_loop_lightweight
0201 
0202     cmpwi   r3, RESUME_GUEST_NV
0203     beq kvm_loop_heavyweight
0204 
0205 kvm_exit_loop:
0206 
0207     PPC_LL  r4, _LINK(r1)
0208     mtlr    r4
0209 
0210     lwz r14, _CCR(r1)
0211     mtcr    r14
0212 
0213     /* Restore non-volatile host registers (r14 - r31) */
0214     REST_NVGPRS(r1)
0215 
0216     addi    r1, r1, SWITCH_FRAME_SIZE
0217     blr
0218 
0219 kvm_loop_heavyweight:
0220 
0221     PPC_LL  r4, _LINK(r1)
0222     PPC_STL r4, (PPC_LR_STKOFF + SWITCH_FRAME_SIZE)(r1)
0223 
0224     /* Load vcpu */
0225     REST_GPR(3, r1)
0226 
0227     /* Load non-volatile guest state from the vcpu */
0228     VCPU_LOAD_NVGPRS(r3)
0229 
0230     /* Jump back into the beginning of this function */
0231     b   kvm_start_lightweight
0232 
0233 kvm_loop_lightweight:
0234 
0235     /* We'll need the vcpu pointer */
0236     REST_GPR(3, r1)
0237 
0238     /* Jump back into the beginning of this function */
0239     b   kvm_start_lightweight