Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0-or-later */
0002 /*
0003  * This file contains the generic code to perform a call to the
0004  * pSeries LPAR hypervisor.
0005  */
0006 #include <linux/jump_label.h>
0007 #include <asm/hvcall.h>
0008 #include <asm/processor.h>
0009 #include <asm/ppc_asm.h>
0010 #include <asm/asm-offsets.h>
0011 #include <asm/ptrace.h>
0012 #include <asm/feature-fixups.h>
0013 
0014     .section    ".text"
0015     
0016 #ifdef CONFIG_TRACEPOINTS
0017 
0018 #ifndef CONFIG_JUMP_LABEL
0019     .section    ".toc","aw"
0020 
0021     .globl hcall_tracepoint_refcount
0022 hcall_tracepoint_refcount:
0023     .8byte  0
0024 
0025     .section    ".text"
0026 #endif
0027 
0028 /*
0029  * precall must preserve all registers.  use unused STK_PARAM()
0030  * areas to save snapshots and opcode.
0031  */
0032 #define HCALL_INST_PRECALL(FIRST_REG)               \
0033     mflr    r0;                     \
0034     std r3,STK_PARAM(R3)(r1);               \
0035     std r4,STK_PARAM(R4)(r1);               \
0036     std r5,STK_PARAM(R5)(r1);               \
0037     std r6,STK_PARAM(R6)(r1);               \
0038     std r7,STK_PARAM(R7)(r1);               \
0039     std r8,STK_PARAM(R8)(r1);               \
0040     std r9,STK_PARAM(R9)(r1);               \
0041     std r10,STK_PARAM(R10)(r1);             \
0042     std r0,16(r1);                  \
0043     addi    r4,r1,STK_PARAM(FIRST_REG);         \
0044     stdu    r1,-STACK_FRAME_OVERHEAD(r1);           \
0045     bl  __trace_hcall_entry;                \
0046     ld  r3,STACK_FRAME_OVERHEAD+STK_PARAM(R3)(r1);  \
0047     ld  r4,STACK_FRAME_OVERHEAD+STK_PARAM(R4)(r1);  \
0048     ld  r5,STACK_FRAME_OVERHEAD+STK_PARAM(R5)(r1);  \
0049     ld  r6,STACK_FRAME_OVERHEAD+STK_PARAM(R6)(r1);  \
0050     ld  r7,STACK_FRAME_OVERHEAD+STK_PARAM(R7)(r1);  \
0051     ld  r8,STACK_FRAME_OVERHEAD+STK_PARAM(R8)(r1);  \
0052     ld  r9,STACK_FRAME_OVERHEAD+STK_PARAM(R9)(r1);  \
0053     ld  r10,STACK_FRAME_OVERHEAD+STK_PARAM(R10)(r1)
0054 
0055 /*
0056  * postcall is performed immediately before function return which
0057  * allows liberal use of volatile registers.
0058  */
0059 #define __HCALL_INST_POSTCALL                   \
0060     ld  r0,STACK_FRAME_OVERHEAD+STK_PARAM(R3)(r1);  \
0061     std r3,STACK_FRAME_OVERHEAD+STK_PARAM(R3)(r1);  \
0062     mr  r4,r3;                      \
0063     mr  r3,r0;                      \
0064     bl  __trace_hcall_exit;             \
0065     ld  r0,STACK_FRAME_OVERHEAD+16(r1);         \
0066     addi    r1,r1,STACK_FRAME_OVERHEAD;         \
0067     ld  r3,STK_PARAM(R3)(r1);               \
0068     mtlr    r0
0069 
0070 #define HCALL_INST_POSTCALL_NORETS              \
0071     li  r5,0;                       \
0072     __HCALL_INST_POSTCALL
0073 
0074 #define HCALL_INST_POSTCALL(BUFREG)             \
0075     mr  r5,BUFREG;                  \
0076     __HCALL_INST_POSTCALL
0077 
0078 #ifdef CONFIG_JUMP_LABEL
0079 #define HCALL_BRANCH(LABEL)                 \
0080     ARCH_STATIC_BRANCH(LABEL, hcall_tracepoint_key)
0081 #else
0082 
0083 /*
0084  * We branch around this in early init (eg when populating the MMU
0085  * hashtable) by using an unconditional cpu feature.
0086  */
0087 #define HCALL_BRANCH(LABEL)                 \
0088 BEGIN_FTR_SECTION;                      \
0089     b   1f;                     \
0090 END_FTR_SECTION(0, 1);                      \
0091     ld  r12,hcall_tracepoint_refcount@toc(r2);      \
0092     std r12,32(r1);                 \
0093     cmpdi   r12,0;                      \
0094     bne-    LABEL;                      \
0095 1:
0096 #endif
0097 
0098 #else
0099 #define HCALL_INST_PRECALL(FIRST_ARG)
0100 #define HCALL_INST_POSTCALL_NORETS
0101 #define HCALL_INST_POSTCALL(BUFREG)
0102 #define HCALL_BRANCH(LABEL)
0103 #endif
0104 
0105 _GLOBAL_TOC(plpar_hcall_norets_notrace)
0106     HMT_MEDIUM
0107 
0108     mfcr    r0
0109     stw r0,8(r1)
0110     HVSC                /* invoke the hypervisor */
0111 
0112     li  r4,0
0113     stb r4,PACASRR_VALID(r13)
0114 
0115     lwz r0,8(r1)
0116     mtcrf   0xff,r0
0117     blr             /* return r3 = status */
0118 
0119 _GLOBAL_TOC(plpar_hcall_norets)
0120     HMT_MEDIUM
0121 
0122     mfcr    r0
0123     stw r0,8(r1)
0124     HCALL_BRANCH(plpar_hcall_norets_trace)
0125     HVSC                /* invoke the hypervisor */
0126 
0127     li  r4,0
0128     stb r4,PACASRR_VALID(r13)
0129 
0130     lwz r0,8(r1)
0131     mtcrf   0xff,r0
0132     blr             /* return r3 = status */
0133 
0134 #ifdef CONFIG_TRACEPOINTS
0135 plpar_hcall_norets_trace:
0136     HCALL_INST_PRECALL(R4)
0137     HVSC
0138     HCALL_INST_POSTCALL_NORETS
0139 
0140     li  r4,0
0141     stb r4,PACASRR_VALID(r13)
0142 
0143     lwz r0,8(r1)
0144     mtcrf   0xff,r0
0145     blr
0146 #endif
0147 
0148 _GLOBAL_TOC(plpar_hcall)
0149     HMT_MEDIUM
0150 
0151     mfcr    r0
0152     stw r0,8(r1)
0153 
0154     HCALL_BRANCH(plpar_hcall_trace)
0155 
0156     std     r4,STK_PARAM(R4)(r1)     /* Save ret buffer */
0157 
0158     mr  r4,r5
0159     mr  r5,r6
0160     mr  r6,r7
0161     mr  r7,r8
0162     mr  r8,r9
0163     mr  r9,r10
0164 
0165     HVSC                /* invoke the hypervisor */
0166 
0167     ld  r12,STK_PARAM(R4)(r1)
0168     std r4,  0(r12)
0169     std r5,  8(r12)
0170     std r6, 16(r12)
0171     std r7, 24(r12)
0172 
0173     li  r4,0
0174     stb r4,PACASRR_VALID(r13)
0175 
0176     lwz r0,8(r1)
0177     mtcrf   0xff,r0
0178 
0179     blr             /* return r3 = status */
0180 
0181 #ifdef CONFIG_TRACEPOINTS
0182 plpar_hcall_trace:
0183     HCALL_INST_PRECALL(R5)
0184 
0185     std r4,STK_PARAM(R4)(r1)
0186     mr  r0,r4
0187 
0188     mr  r4,r5
0189     mr  r5,r6
0190     mr  r6,r7
0191     mr  r7,r8
0192     mr  r8,r9
0193     mr  r9,r10
0194 
0195     HVSC
0196 
0197     ld  r12,STK_PARAM(R4)(r1)
0198     std r4,0(r12)
0199     std r5,8(r12)
0200     std r6,16(r12)
0201     std r7,24(r12)
0202 
0203     HCALL_INST_POSTCALL(r12)
0204 
0205     li  r4,0
0206     stb r4,PACASRR_VALID(r13)
0207 
0208     lwz r0,8(r1)
0209     mtcrf   0xff,r0
0210 
0211     blr
0212 #endif
0213 
0214 /*
0215  * plpar_hcall_raw can be called in real mode. kexec/kdump need some
0216  * hypervisor calls to be executed in real mode. So plpar_hcall_raw
0217  * does not access the per cpu hypervisor call statistics variables,
0218  * since these variables may not be present in the RMO region.
0219  */
0220 _GLOBAL(plpar_hcall_raw)
0221     HMT_MEDIUM
0222 
0223     mfcr    r0
0224     stw r0,8(r1)
0225 
0226     std     r4,STK_PARAM(R4)(r1)     /* Save ret buffer */
0227 
0228     mr  r4,r5
0229     mr  r5,r6
0230     mr  r6,r7
0231     mr  r7,r8
0232     mr  r8,r9
0233     mr  r9,r10
0234 
0235     HVSC                /* invoke the hypervisor */
0236 
0237     ld  r12,STK_PARAM(R4)(r1)
0238     std r4,  0(r12)
0239     std r5,  8(r12)
0240     std r6, 16(r12)
0241     std r7, 24(r12)
0242 
0243     li  r4,0
0244     stb r4,PACASRR_VALID(r13)
0245 
0246     lwz r0,8(r1)
0247     mtcrf   0xff,r0
0248 
0249     blr             /* return r3 = status */
0250 
0251 _GLOBAL_TOC(plpar_hcall9)
0252     HMT_MEDIUM
0253 
0254     mfcr    r0
0255     stw r0,8(r1)
0256 
0257     HCALL_BRANCH(plpar_hcall9_trace)
0258 
0259     std     r4,STK_PARAM(R4)(r1)     /* Save ret buffer */
0260 
0261     mr  r4,r5
0262     mr  r5,r6
0263     mr  r6,r7
0264     mr  r7,r8
0265     mr  r8,r9
0266     mr  r9,r10
0267     ld  r10,STK_PARAM(R11)(r1)   /* put arg7 in R10 */
0268     ld  r11,STK_PARAM(R12)(r1)   /* put arg8 in R11 */
0269     ld  r12,STK_PARAM(R13)(r1)    /* put arg9 in R12 */
0270 
0271     HVSC                /* invoke the hypervisor */
0272 
0273     mr  r0,r12
0274     ld  r12,STK_PARAM(R4)(r1)
0275     std r4,  0(r12)
0276     std r5,  8(r12)
0277     std r6, 16(r12)
0278     std r7, 24(r12)
0279     std r8, 32(r12)
0280     std r9, 40(r12)
0281     std r10,48(r12)
0282     std r11,56(r12)
0283     std r0, 64(r12)
0284 
0285     li  r4,0
0286     stb r4,PACASRR_VALID(r13)
0287 
0288     lwz r0,8(r1)
0289     mtcrf   0xff,r0
0290 
0291     blr             /* return r3 = status */
0292 
0293 #ifdef CONFIG_TRACEPOINTS
0294 plpar_hcall9_trace:
0295     HCALL_INST_PRECALL(R5)
0296 
0297     std r4,STK_PARAM(R4)(r1)
0298     mr  r0,r4
0299 
0300     mr  r4,r5
0301     mr  r5,r6
0302     mr  r6,r7
0303     mr  r7,r8
0304     mr  r8,r9
0305     mr  r9,r10
0306     ld  r10,STACK_FRAME_OVERHEAD+STK_PARAM(R11)(r1)
0307     ld  r11,STACK_FRAME_OVERHEAD+STK_PARAM(R12)(r1)
0308     ld  r12,STACK_FRAME_OVERHEAD+STK_PARAM(R13)(r1)
0309 
0310     HVSC
0311 
0312     mr  r0,r12
0313     ld  r12,STACK_FRAME_OVERHEAD+STK_PARAM(R4)(r1)
0314     std r4,0(r12)
0315     std r5,8(r12)
0316     std r6,16(r12)
0317     std r7,24(r12)
0318     std r8,32(r12)
0319     std r9,40(r12)
0320     std r10,48(r12)
0321     std r11,56(r12)
0322     std r0,64(r12)
0323 
0324     HCALL_INST_POSTCALL(r12)
0325 
0326     li  r4,0
0327     stb r4,PACASRR_VALID(r13)
0328 
0329     lwz r0,8(r1)
0330     mtcrf   0xff,r0
0331 
0332     blr
0333 #endif
0334 
0335 /* See plpar_hcall_raw to see why this is needed */
0336 _GLOBAL(plpar_hcall9_raw)
0337     HMT_MEDIUM
0338 
0339     mfcr    r0
0340     stw r0,8(r1)
0341 
0342     std     r4,STK_PARAM(R4)(r1)     /* Save ret buffer */
0343 
0344     mr  r4,r5
0345     mr  r5,r6
0346     mr  r6,r7
0347     mr  r7,r8
0348     mr  r8,r9
0349     mr  r9,r10
0350     ld  r10,STK_PARAM(R11)(r1)   /* put arg7 in R10 */
0351     ld  r11,STK_PARAM(R12)(r1)   /* put arg8 in R11 */
0352     ld  r12,STK_PARAM(R13)(r1)    /* put arg9 in R12 */
0353 
0354     HVSC                /* invoke the hypervisor */
0355 
0356     mr  r0,r12
0357     ld  r12,STK_PARAM(R4)(r1)
0358     std r4,  0(r12)
0359     std r5,  8(r12)
0360     std r6, 16(r12)
0361     std r7, 24(r12)
0362     std r8, 32(r12)
0363     std r9, 40(r12)
0364     std r10,48(r12)
0365     std r11,56(r12)
0366     std r0, 64(r12)
0367 
0368     li  r4,0
0369     stb r4,PACASRR_VALID(r13)
0370 
0371     lwz r0,8(r1)
0372     mtcrf   0xff,r0
0373 
0374     blr             /* return r3 = status */