1/* SPDX-License-Identifier: GPL-2.0-or-later */ 2/* 3 * FPU helper code to use FPU operations from inside the kernel 4 * 5 * Copyright (C) 2010 Alexander Graf (agraf@suse.de) 6 */ 7 8#include <linux/pgtable.h> 9#include <asm/reg.h> 10#include <asm/page.h> 11#include <asm/mmu.h> 12#include <asm/cputable.h> 13#include <asm/cache.h> 14#include <asm/thread_info.h> 15#include <asm/ppc_asm.h> 16#include <asm/asm-offsets.h> 17 18/* Instructions operating on single parameters */ 19 20/* 21 * Single operation with one input operand 22 * 23 * R3 = (double*)&fpscr 24 * R4 = (short*)&result 25 * R5 = (short*)¶m1 26 */ 27#define FPS_ONE_IN(name) \ 28_GLOBAL(fps_ ## name); \ 29 lfd 0,0(r3); /* load up fpscr value */ \ 30 MTFSF_L(0); \ 31 lfs 0,0(r5); \ 32 \ 33 name 0,0; \ 34 \ 35 stfs 0,0(r4); \ 36 mffs 0; \ 37 stfd 0,0(r3); /* save new fpscr value */ \ 38 blr 39 40/* 41 * Single operation with two input operands 42 * 43 * R3 = (double*)&fpscr 44 * R4 = (short*)&result 45 * R5 = (short*)¶m1 46 * R6 = (short*)¶m2 47 */ 48#define FPS_TWO_IN(name) \ 49_GLOBAL(fps_ ## name); \ 50 lfd 0,0(r3); /* load up fpscr value */ \ 51 MTFSF_L(0); \ 52 lfs 0,0(r5); \ 53 lfs 1,0(r6); \ 54 \ 55 name 0,0,1; \ 56 \ 57 stfs 0,0(r4); \ 58 mffs 0; \ 59 stfd 0,0(r3); /* save new fpscr value */ \ 60 blr 61 62/* 63 * Single operation with three input operands 64 * 65 * R3 = (double*)&fpscr 66 * R4 = (short*)&result 67 * R5 = (short*)¶m1 68 * R6 = (short*)¶m2 69 * R7 = (short*)¶m3 70 */ 71#define FPS_THREE_IN(name) \ 72_GLOBAL(fps_ ## name); \ 73 lfd 0,0(r3); /* load up fpscr value */ \ 74 MTFSF_L(0); \ 75 lfs 0,0(r5); \ 76 lfs 1,0(r6); \ 77 lfs 2,0(r7); \ 78 \ 79 name 0,0,1,2; \ 80 \ 81 stfs 0,0(r4); \ 82 mffs 0; \ 83 stfd 0,0(r3); /* save new fpscr value */ \ 84 blr 85 86FPS_ONE_IN(fres) 87FPS_ONE_IN(frsqrte) 88FPS_ONE_IN(fsqrts) 89FPS_TWO_IN(fadds) 90FPS_TWO_IN(fdivs) 91FPS_TWO_IN(fmuls) 92FPS_TWO_IN(fsubs) 93FPS_THREE_IN(fmadds) 94FPS_THREE_IN(fmsubs) 95FPS_THREE_IN(fnmadds) 96FPS_THREE_IN(fnmsubs) 97FPS_THREE_IN(fsel) 98 99 100/* Instructions operating on double parameters */ 101 102/* 103 * Beginning of double instruction processing 104 * 105 * R3 = (double*)&fpscr 106 * R4 = (u32*)&cr 107 * R5 = (double*)&result 108 * R6 = (double*)¶m1 109 * R7 = (double*)¶m2 [load_two] 110 * R8 = (double*)¶m3 [load_three] 111 * LR = instruction call function 112 */ 113fpd_load_three: 114 lfd 2,0(r8) /* load param3 */ 115fpd_load_two: 116 lfd 1,0(r7) /* load param2 */ 117fpd_load_one: 118 lfd 0,0(r6) /* load param1 */ 119fpd_load_none: 120 lfd 3,0(r3) /* load up fpscr value */ 121 MTFSF_L(3) 122 lwz r6, 0(r4) /* load cr */ 123 mtcr r6 124 blr 125 126/* 127 * End of double instruction processing 128 * 129 * R3 = (double*)&fpscr 130 * R4 = (u32*)&cr 131 * R5 = (double*)&result 132 * LR = caller of instruction call function 133 */ 134fpd_return: 135 mfcr r6 136 stfd 0,0(r5) /* save result */ 137 mffs 0 138 stfd 0,0(r3) /* save new fpscr value */ 139 stw r6,0(r4) /* save new cr value */ 140 blr 141 142/* 143 * Double operation with no input operand 144 * 145 * R3 = (double*)&fpscr 146 * R4 = (u32*)&cr 147 * R5 = (double*)&result 148 */ 149#define FPD_NONE_IN(name) \ 150_GLOBAL(fpd_ ## name); \ 151 mflr r12; \ 152 bl fpd_load_none; \ 153 mtlr r12; \ 154 \ 155 name. 0; /* call instruction */ \ 156 b fpd_return 157 158/* 159 * Double operation with one input operand 160 * 161 * R3 = (double*)&fpscr 162 * R4 = (u32*)&cr 163 * R5 = (double*)&result 164 * R6 = (double*)¶m1 165 */ 166#define FPD_ONE_IN(name) \ 167_GLOBAL(fpd_ ## name); \ 168 mflr r12; \ 169 bl fpd_load_one; \ 170 mtlr r12; \ 171 \ 172 name. 0,0; /* call instruction */ \ 173 b fpd_return 174 175/* 176 * Double operation with two input operands 177 * 178 * R3 = (double*)&fpscr 179 * R4 = (u32*)&cr 180 * R5 = (double*)&result 181 * R6 = (double*)¶m1 182 * R7 = (double*)¶m2 183 * R8 = (double*)¶m3 184 */ 185#define FPD_TWO_IN(name) \ 186_GLOBAL(fpd_ ## name); \ 187 mflr r12; \ 188 bl fpd_load_two; \ 189 mtlr r12; \ 190 \ 191 name. 0,0,1; /* call instruction */ \ 192 b fpd_return 193 194/* 195 * CR Double operation with two input operands 196 * 197 * R3 = (double*)&fpscr 198 * R4 = (u32*)&cr 199 * R5 = (double*)¶m1 200 * R6 = (double*)¶m2 201 * R7 = (double*)¶m3 202 */ 203#define FPD_TWO_IN_CR(name) \ 204_GLOBAL(fpd_ ## name); \ 205 lfd 1,0(r6); /* load param2 */ \ 206 lfd 0,0(r5); /* load param1 */ \ 207 lfd 3,0(r3); /* load up fpscr value */ \ 208 MTFSF_L(3); \ 209 lwz r6, 0(r4); /* load cr */ \ 210 mtcr r6; \ 211 \ 212 name 0,0,1; /* call instruction */ \ 213 mfcr r6; \ 214 mffs 0; \ 215 stfd 0,0(r3); /* save new fpscr value */ \ 216 stw r6,0(r4); /* save new cr value */ \ 217 blr 218 219/* 220 * Double operation with three input operands 221 * 222 * R3 = (double*)&fpscr 223 * R4 = (u32*)&cr 224 * R5 = (double*)&result 225 * R6 = (double*)¶m1 226 * R7 = (double*)¶m2 227 * R8 = (double*)¶m3 228 */ 229#define FPD_THREE_IN(name) \ 230_GLOBAL(fpd_ ## name); \ 231 mflr r12; \ 232 bl fpd_load_three; \ 233 mtlr r12; \ 234 \ 235 name. 0,0,1,2; /* call instruction */ \ 236 b fpd_return 237 238FPD_ONE_IN(fsqrts) 239FPD_ONE_IN(frsqrtes) 240FPD_ONE_IN(fres) 241FPD_ONE_IN(frsp) 242FPD_ONE_IN(fctiw) 243FPD_ONE_IN(fctiwz) 244FPD_ONE_IN(fsqrt) 245FPD_ONE_IN(fre) 246FPD_ONE_IN(frsqrte) 247FPD_ONE_IN(fneg) 248FPD_ONE_IN(fabs) 249FPD_TWO_IN(fadds) 250FPD_TWO_IN(fsubs) 251FPD_TWO_IN(fdivs) 252FPD_TWO_IN(fmuls) 253FPD_TWO_IN_CR(fcmpu) 254FPD_TWO_IN(fcpsgn) 255FPD_TWO_IN(fdiv) 256FPD_TWO_IN(fadd) 257FPD_TWO_IN(fmul) 258FPD_TWO_IN_CR(fcmpo) 259FPD_TWO_IN(fsub) 260FPD_THREE_IN(fmsubs) 261FPD_THREE_IN(fmadds) 262FPD_THREE_IN(fnmsubs) 263FPD_THREE_IN(fnmadds) 264FPD_THREE_IN(fsel) 265FPD_THREE_IN(fmsub) 266FPD_THREE_IN(fmadd) 267FPD_THREE_IN(fnmsub) 268FPD_THREE_IN(fnmadd) 269 270_GLOBAL(kvm_cvt_fd) 271 lfs 0,0(r3) 272 stfd 0,0(r4) 273 blr 274 275_GLOBAL(kvm_cvt_df) 276 lfd 0,0(r3) 277 stfs 0,0(r4) 278 blr 279