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