1 /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 /* 3 * This file contains the generic code to perform a call to the 4 * pSeries LPAR hypervisor. 5 */ 6 #include <linux/jump_label.h> 7 #include <asm/hvcall.h> 8 #include <asm/processor.h> 9 #include <asm/ppc_asm.h> 10 #include <asm/asm-offsets.h> 11 #include <asm/ptrace.h> 12 #include <asm/feature-fixups.h> 13 14 .section ".text" 15 16 #ifdef CONFIG_TRACEPOINTS 17 18 #ifndef CONFIG_JUMP_LABEL 19 .data 20 21 .globl hcall_tracepoint_refcount 22 hcall_tracepoint_refcount: 23 .8byte 0 24 25 .section ".text" 26 #endif 27 28 /* 29 * precall must preserve all registers. use unused STK_PARAM() 30 * areas to save snapshots and opcode. STK_PARAM() in the caller's 31 * frame will be available even on ELFv2 because these are all 32 * variadic functions. 33 */ 34 #define HCALL_INST_PRECALL(FIRST_REG) \ 35 mflr r0; \ 36 std r3,STK_PARAM(R3)(r1); \ 37 std r4,STK_PARAM(R4)(r1); \ 38 std r5,STK_PARAM(R5)(r1); \ 39 std r6,STK_PARAM(R6)(r1); \ 40 std r7,STK_PARAM(R7)(r1); \ 41 std r8,STK_PARAM(R8)(r1); \ 42 std r9,STK_PARAM(R9)(r1); \ 43 std r10,STK_PARAM(R10)(r1); \ 44 std r0,16(r1); \ 45 addi r4,r1,STK_PARAM(FIRST_REG); \ 46 stdu r1,-STACK_FRAME_MIN_SIZE(r1); \ 47 bl CFUNC(__trace_hcall_entry); \ 48 ld r3,STACK_FRAME_MIN_SIZE+STK_PARAM(R3)(r1); \ 49 ld r4,STACK_FRAME_MIN_SIZE+STK_PARAM(R4)(r1); \ 50 ld r5,STACK_FRAME_MIN_SIZE+STK_PARAM(R5)(r1); \ 51 ld r6,STACK_FRAME_MIN_SIZE+STK_PARAM(R6)(r1); \ 52 ld r7,STACK_FRAME_MIN_SIZE+STK_PARAM(R7)(r1); \ 53 ld r8,STACK_FRAME_MIN_SIZE+STK_PARAM(R8)(r1); \ 54 ld r9,STACK_FRAME_MIN_SIZE+STK_PARAM(R9)(r1); \ 55 ld r10,STACK_FRAME_MIN_SIZE+STK_PARAM(R10)(r1) 56 57 /* 58 * postcall is performed immediately before function return which 59 * allows liberal use of volatile registers. 60 */ 61 #define __HCALL_INST_POSTCALL \ 62 ld r0,STACK_FRAME_MIN_SIZE+STK_PARAM(R3)(r1); \ 63 std r3,STACK_FRAME_MIN_SIZE+STK_PARAM(R3)(r1); \ 64 mr r4,r3; \ 65 mr r3,r0; \ 66 bl CFUNC(__trace_hcall_exit); \ 67 ld r0,STACK_FRAME_MIN_SIZE+16(r1); \ 68 addi r1,r1,STACK_FRAME_MIN_SIZE; \ 69 ld r3,STK_PARAM(R3)(r1); \ 70 mtlr r0 71 72 #define HCALL_INST_POSTCALL_NORETS \ 73 li r5,0; \ 74 __HCALL_INST_POSTCALL 75 76 #define HCALL_INST_POSTCALL(BUFREG) \ 77 mr r5,BUFREG; \ 78 __HCALL_INST_POSTCALL 79 80 #ifdef CONFIG_JUMP_LABEL 81 #define HCALL_BRANCH(LABEL) \ 82 ARCH_STATIC_BRANCH(LABEL, hcall_tracepoint_key) 83 #else 84 85 /* 86 * We branch around this in early init (eg when populating the MMU 87 * hashtable) by using an unconditional cpu feature. 88 */ 89 #define HCALL_BRANCH(LABEL) \ 90 BEGIN_FTR_SECTION; \ 91 b 1f; \ 92 END_FTR_SECTION(0, 1); \ 93 LOAD_REG_ADDR(r12, hcall_tracepoint_refcount) ; \ 94 ld r12,0(r12); \ 95 cmpdi r12,0; \ 96 bne- LABEL; \ 97 1: 98 #endif 99 100 #else 101 #define HCALL_INST_PRECALL(FIRST_ARG) 102 #define HCALL_INST_POSTCALL_NORETS 103 #define HCALL_INST_POSTCALL(BUFREG) 104 #define HCALL_BRANCH(LABEL) 105 #endif 106 107 _GLOBAL_TOC(plpar_hcall_norets_notrace) 108 HMT_MEDIUM 109 110 mfcr r0 111 stw r0,8(r1) 112 HVSC /* invoke the hypervisor */ 113 114 li r4,0 115 stb r4,PACASRR_VALID(r13) 116 117 lwz r0,8(r1) 118 mtcrf 0xff,r0 119 blr /* return r3 = status */ 120 121 _GLOBAL_TOC(plpar_hcall_norets) 122 HMT_MEDIUM 123 124 mfcr r0 125 stw r0,8(r1) 126 HCALL_BRANCH(plpar_hcall_norets_trace) 127 HVSC /* invoke the hypervisor */ 128 129 li r4,0 130 stb r4,PACASRR_VALID(r13) 131 132 lwz r0,8(r1) 133 mtcrf 0xff,r0 134 blr /* return r3 = status */ 135 136 #ifdef CONFIG_TRACEPOINTS 137 plpar_hcall_norets_trace: 138 HCALL_INST_PRECALL(R4) 139 HVSC 140 HCALL_INST_POSTCALL_NORETS 141 142 li r4,0 143 stb r4,PACASRR_VALID(r13) 144 145 lwz r0,8(r1) 146 mtcrf 0xff,r0 147 blr 148 #endif 149 150 _GLOBAL_TOC(plpar_hcall) 151 HMT_MEDIUM 152 153 mfcr r0 154 stw r0,8(r1) 155 156 HCALL_BRANCH(plpar_hcall_trace) 157 158 std r4,STK_PARAM(R4)(r1) /* Save ret buffer */ 159 160 mr r4,r5 161 mr r5,r6 162 mr r6,r7 163 mr r7,r8 164 mr r8,r9 165 mr r9,r10 166 167 HVSC /* invoke the hypervisor */ 168 169 ld r12,STK_PARAM(R4)(r1) 170 std r4, 0(r12) 171 std r5, 8(r12) 172 std r6, 16(r12) 173 std r7, 24(r12) 174 175 li r4,0 176 stb r4,PACASRR_VALID(r13) 177 178 lwz r0,8(r1) 179 mtcrf 0xff,r0 180 181 blr /* return r3 = status */ 182 183 #ifdef CONFIG_TRACEPOINTS 184 plpar_hcall_trace: 185 HCALL_INST_PRECALL(R5) 186 187 mr r4,r5 188 mr r5,r6 189 mr r6,r7 190 mr r7,r8 191 mr r8,r9 192 mr r9,r10 193 194 HVSC 195 196 ld r12,STACK_FRAME_MIN_SIZE+STK_PARAM(R4)(r1) 197 std r4,0(r12) 198 std r5,8(r12) 199 std r6,16(r12) 200 std r7,24(r12) 201 202 HCALL_INST_POSTCALL(r12) 203 204 li r4,0 205 stb r4,PACASRR_VALID(r13) 206 207 lwz r0,8(r1) 208 mtcrf 0xff,r0 209 210 blr 211 #endif 212 213 /* 214 * plpar_hcall_raw can be called in real mode. kexec/kdump need some 215 * hypervisor calls to be executed in real mode. So plpar_hcall_raw 216 * does not access the per cpu hypervisor call statistics variables, 217 * since these variables may not be present in the RMO region. 218 */ 219 _GLOBAL(plpar_hcall_raw) 220 HMT_MEDIUM 221 222 mfcr r0 223 stw r0,8(r1) 224 225 std r4,STK_PARAM(R4)(r1) /* Save ret buffer */ 226 227 mr r4,r5 228 mr r5,r6 229 mr r6,r7 230 mr r7,r8 231 mr r8,r9 232 mr r9,r10 233 234 HVSC /* invoke the hypervisor */ 235 236 ld r12,STK_PARAM(R4)(r1) 237 std r4, 0(r12) 238 std r5, 8(r12) 239 std r6, 16(r12) 240 std r7, 24(r12) 241 242 li r4,0 243 stb r4,PACASRR_VALID(r13) 244 245 lwz r0,8(r1) 246 mtcrf 0xff,r0 247 248 blr /* return r3 = status */ 249 250 _GLOBAL_TOC(plpar_hcall9) 251 HMT_MEDIUM 252 253 mfcr r0 254 stw r0,8(r1) 255 256 HCALL_BRANCH(plpar_hcall9_trace) 257 258 std r4,STK_PARAM(R4)(r1) /* Save ret buffer */ 259 260 mr r4,r5 261 mr r5,r6 262 mr r6,r7 263 mr r7,r8 264 mr r8,r9 265 mr r9,r10 266 ld r10,STK_PARAM(R11)(r1) /* put arg7 in R10 */ 267 ld r11,STK_PARAM(R12)(r1) /* put arg8 in R11 */ 268 ld r12,STK_PARAM(R13)(r1) /* put arg9 in R12 */ 269 270 HVSC /* invoke the hypervisor */ 271 272 mr r0,r12 273 ld r12,STK_PARAM(R4)(r1) 274 std r4, 0(r12) 275 std r5, 8(r12) 276 std r6, 16(r12) 277 std r7, 24(r12) 278 std r8, 32(r12) 279 std r9, 40(r12) 280 std r10,48(r12) 281 std r11,56(r12) 282 std r0, 64(r12) 283 284 li r4,0 285 stb r4,PACASRR_VALID(r13) 286 287 lwz r0,8(r1) 288 mtcrf 0xff,r0 289 290 blr /* return r3 = status */ 291 292 #ifdef CONFIG_TRACEPOINTS 293 plpar_hcall9_trace: 294 HCALL_INST_PRECALL(R5) 295 296 mr r4,r5 297 mr r5,r6 298 mr r6,r7 299 mr r7,r8 300 mr r8,r9 301 mr r9,r10 302 ld r10,STACK_FRAME_MIN_SIZE+STK_PARAM(R11)(r1) 303 ld r11,STACK_FRAME_MIN_SIZE+STK_PARAM(R12)(r1) 304 ld r12,STACK_FRAME_MIN_SIZE+STK_PARAM(R13)(r1) 305 306 HVSC 307 308 mr r0,r12 309 ld r12,STACK_FRAME_MIN_SIZE+STK_PARAM(R4)(r1) 310 std r4,0(r12) 311 std r5,8(r12) 312 std r6,16(r12) 313 std r7,24(r12) 314 std r8,32(r12) 315 std r9,40(r12) 316 std r10,48(r12) 317 std r11,56(r12) 318 std r0,64(r12) 319 320 HCALL_INST_POSTCALL(r12) 321 322 li r4,0 323 stb r4,PACASRR_VALID(r13) 324 325 lwz r0,8(r1) 326 mtcrf 0xff,r0 327 328 blr 329 #endif 330 331 /* See plpar_hcall_raw to see why this is needed */ 332 _GLOBAL(plpar_hcall9_raw) 333 HMT_MEDIUM 334 335 mfcr r0 336 stw r0,8(r1) 337 338 std r4,STK_PARAM(R4)(r1) /* Save ret buffer */ 339 340 mr r4,r5 341 mr r5,r6 342 mr r6,r7 343 mr r7,r8 344 mr r8,r9 345 mr r9,r10 346 ld r10,STK_PARAM(R11)(r1) /* put arg7 in R10 */ 347 ld r11,STK_PARAM(R12)(r1) /* put arg8 in R11 */ 348 ld r12,STK_PARAM(R13)(r1) /* put arg9 in R12 */ 349 350 HVSC /* invoke the hypervisor */ 351 352 mr r0,r12 353 ld r12,STK_PARAM(R4)(r1) 354 std r4, 0(r12) 355 std r5, 8(r12) 356 std r6, 16(r12) 357 std r7, 24(r12) 358 std r8, 32(r12) 359 std r9, 40(r12) 360 std r10,48(r12) 361 std r11,56(r12) 362 std r0, 64(r12) 363 364 li r4,0 365 stb r4,PACASRR_VALID(r13) 366 367 lwz r0,8(r1) 368 mtcrf 0xff,r0 369 370 blr /* return r3 = status */
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.