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