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