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 <asm/hvcall.h> 11#include <asm/processor.h> 12#include <asm/ppc_asm.h> 13#include <asm/asm-offsets.h> 14 15#define STK_PARM(i) (48 + ((i)-3)*8) 16 17#ifdef CONFIG_HCALL_STATS 18/* 19 * precall must preserve all registers. use unused STK_PARM() 20 * areas to save snapshots and opcode. 21 */ 22#define HCALL_INST_PRECALL \ 23 std r3,STK_PARM(r3)(r1); /* save opcode */ \ 24 mftb r0; /* get timebase and */ \ 25 std r0,STK_PARM(r5)(r1); /* save for later */ \ 26BEGIN_FTR_SECTION; \ 27 mfspr r0,SPRN_PURR; /* get PURR and */ \ 28 std r0,STK_PARM(r6)(r1); /* save for later */ \ 29END_FTR_SECTION_IFSET(CPU_FTR_PURR); 30 31/* 32 * postcall is performed immediately before function return which 33 * allows liberal use of volatile registers. We branch around this 34 * in early init (eg when populating the MMU hashtable) by using an 35 * unconditional cpu feature. 36 */ 37#define HCALL_INST_POSTCALL \ 38BEGIN_FTR_SECTION; \ 39 b 1f; \ 40END_FTR_SECTION(0, 1); \ 41 ld r4,STK_PARM(r3)(r1); /* validate opcode */ \ 42 cmpldi cr7,r4,MAX_HCALL_OPCODE; \ 43 bgt- cr7,1f; \ 44 \ 45 /* get time and PURR snapshots after hcall */ \ 46 mftb r7; /* timebase after */ \ 47BEGIN_FTR_SECTION; \ 48 mfspr r8,SPRN_PURR; /* PURR after */ \ 49 ld r6,STK_PARM(r6)(r1); /* PURR before */ \ 50 subf r6,r6,r8; /* delta */ \ 51END_FTR_SECTION_IFSET(CPU_FTR_PURR); \ 52 ld r5,STK_PARM(r5)(r1); /* timebase before */ \ 53 subf r5,r5,r7; /* time delta */ \ 54 \ 55 /* calculate address of stat structure r4 = opcode */ \ 56 srdi r4,r4,2; /* index into array */ \ 57 mulli r4,r4,HCALL_STAT_SIZE; \ 58 LOAD_REG_ADDR(r7, per_cpu__hcall_stats); \ 59 add r4,r4,r7; \ 60 ld r7,PACA_DATA_OFFSET(r13); /* per cpu offset */ \ 61 add r4,r4,r7; \ 62 \ 63 /* update stats */ \ 64 ld r7,HCALL_STAT_CALLS(r4); /* count */ \ 65 addi r7,r7,1; \ 66 std r7,HCALL_STAT_CALLS(r4); \ 67 ld r7,HCALL_STAT_TB(r4); /* timebase */ \ 68 add r7,r7,r5; \ 69 std r7,HCALL_STAT_TB(r4); \ 70BEGIN_FTR_SECTION; \ 71 ld r7,HCALL_STAT_PURR(r4); /* PURR */ \ 72 add r7,r7,r6; \ 73 std r7,HCALL_STAT_PURR(r4); \ 74END_FTR_SECTION_IFSET(CPU_FTR_PURR); \ 751: 76#else 77#define HCALL_INST_PRECALL 78#define HCALL_INST_POSTCALL 79#endif 80 81 .text 82 83_GLOBAL(plpar_hcall_norets) 84 HMT_MEDIUM 85 86 mfcr r0 87 stw r0,8(r1) 88 89 HCALL_INST_PRECALL 90 91 HVSC /* invoke the hypervisor */ 92 93 HCALL_INST_POSTCALL 94 95 lwz r0,8(r1) 96 mtcrf 0xff,r0 97 blr /* return r3 = status */ 98 99_GLOBAL(plpar_hcall) 100 HMT_MEDIUM 101 102 mfcr r0 103 stw r0,8(r1) 104 105 HCALL_INST_PRECALL 106 107 std r4,STK_PARM(r4)(r1) /* Save ret buffer */ 108 109 mr r4,r5 110 mr r5,r6 111 mr r6,r7 112 mr r7,r8 113 mr r8,r9 114 mr r9,r10 115 116 HVSC /* invoke the hypervisor */ 117 118 ld r12,STK_PARM(r4)(r1) 119 std r4, 0(r12) 120 std r5, 8(r12) 121 std r6, 16(r12) 122 std r7, 24(r12) 123 124 HCALL_INST_POSTCALL 125 126 lwz r0,8(r1) 127 mtcrf 0xff,r0 128 129 blr /* return r3 = status */ 130 131/* 132 * plpar_hcall_raw can be called in real mode. kexec/kdump need some 133 * hypervisor calls to be executed in real mode. So plpar_hcall_raw 134 * does not access the per cpu hypervisor call statistics variables, 135 * since these variables may not be present in the RMO region. 136 */ 137_GLOBAL(plpar_hcall_raw) 138 HMT_MEDIUM 139 140 mfcr r0 141 stw r0,8(r1) 142 143 std r4,STK_PARM(r4)(r1) /* Save ret buffer */ 144 145 mr r4,r5 146 mr r5,r6 147 mr r6,r7 148 mr r7,r8 149 mr r8,r9 150 mr r9,r10 151 152 HVSC /* invoke the hypervisor */ 153 154 ld r12,STK_PARM(r4)(r1) 155 std r4, 0(r12) 156 std r5, 8(r12) 157 std r6, 16(r12) 158 std r7, 24(r12) 159 160 lwz r0,8(r1) 161 mtcrf 0xff,r0 162 163 blr /* return r3 = status */ 164 165_GLOBAL(plpar_hcall9) 166 HMT_MEDIUM 167 168 mfcr r0 169 stw r0,8(r1) 170 171 HCALL_INST_PRECALL 172 173 std r4,STK_PARM(r4)(r1) /* Save ret buffer */ 174 175 mr r4,r5 176 mr r5,r6 177 mr r6,r7 178 mr r7,r8 179 mr r8,r9 180 mr r9,r10 181 ld r10,STK_PARM(r11)(r1) /* put arg7 in R10 */ 182 ld r11,STK_PARM(r12)(r1) /* put arg8 in R11 */ 183 ld r12,STK_PARM(r13)(r1) /* put arg9 in R12 */ 184 185 HVSC /* invoke the hypervisor */ 186 187 mr r0,r12 188 ld r12,STK_PARM(r4)(r1) 189 std r4, 0(r12) 190 std r5, 8(r12) 191 std r6, 16(r12) 192 std r7, 24(r12) 193 std r8, 32(r12) 194 std r9, 40(r12) 195 std r10,48(r12) 196 std r11,56(r12) 197 std r0, 64(r12) 198 199 HCALL_INST_POSTCALL 200 201 lwz r0,8(r1) 202 mtcrf 0xff,r0 203 204 blr /* return r3 = status */ 205