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