18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Linux/PA-RISC Project (http://www.parisc-linux.org/) 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Floating-point emulation code 68c2ecf20Sopenharmony_ci * Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci/* 98c2ecf20Sopenharmony_ci * linux/arch/math-emu/driver.c.c 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * decodes and dispatches unimplemented FPU instructions 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * Copyright (C) 1999, 2000 Philipp Rumpf <prumpf@tux.org> 148c2ecf20Sopenharmony_ci * Copyright (C) 2001 Hewlett-Packard <bame@debian.org> 158c2ecf20Sopenharmony_ci */ 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <linux/sched/signal.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include "float.h" 208c2ecf20Sopenharmony_ci#include "math-emu.h" 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define fptpos 31 248c2ecf20Sopenharmony_ci#define fpr1pos 10 258c2ecf20Sopenharmony_ci#define extru(r,pos,len) (((r) >> (31-(pos))) & (( 1 << (len)) - 1)) 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#define FPUDEBUG 0 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci/* Format of the floating-point exception registers. */ 308c2ecf20Sopenharmony_cistruct exc_reg { 318c2ecf20Sopenharmony_ci unsigned int exception : 6; 328c2ecf20Sopenharmony_ci unsigned int ei : 26; 338c2ecf20Sopenharmony_ci}; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci/* Macros for grabbing bits of the instruction format from the 'ei' 368c2ecf20Sopenharmony_ci field above. */ 378c2ecf20Sopenharmony_ci/* Major opcode 0c and 0e */ 388c2ecf20Sopenharmony_ci#define FP0CE_UID(i) (((i) >> 6) & 3) 398c2ecf20Sopenharmony_ci#define FP0CE_CLASS(i) (((i) >> 9) & 3) 408c2ecf20Sopenharmony_ci#define FP0CE_SUBOP(i) (((i) >> 13) & 7) 418c2ecf20Sopenharmony_ci#define FP0CE_SUBOP1(i) (((i) >> 15) & 7) /* Class 1 subopcode */ 428c2ecf20Sopenharmony_ci#define FP0C_FORMAT(i) (((i) >> 11) & 3) 438c2ecf20Sopenharmony_ci#define FP0E_FORMAT(i) (((i) >> 11) & 1) 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci/* Major opcode 0c, uid 2 (performance monitoring) */ 468c2ecf20Sopenharmony_ci#define FPPM_SUBOP(i) (((i) >> 9) & 0x1f) 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci/* Major opcode 2e (fused operations). */ 498c2ecf20Sopenharmony_ci#define FP2E_SUBOP(i) (((i) >> 5) & 1) 508c2ecf20Sopenharmony_ci#define FP2E_FORMAT(i) (((i) >> 11) & 1) 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci/* Major opcode 26 (FMPYSUB) */ 538c2ecf20Sopenharmony_ci/* Major opcode 06 (FMPYADD) */ 548c2ecf20Sopenharmony_ci#define FPx6_FORMAT(i) ((i) & 0x1f) 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci/* Flags and enable bits of the status word. */ 578c2ecf20Sopenharmony_ci#define FPSW_FLAGS(w) ((w) >> 27) 588c2ecf20Sopenharmony_ci#define FPSW_ENABLE(w) ((w) & 0x1f) 598c2ecf20Sopenharmony_ci#define FPSW_V (1<<4) 608c2ecf20Sopenharmony_ci#define FPSW_Z (1<<3) 618c2ecf20Sopenharmony_ci#define FPSW_O (1<<2) 628c2ecf20Sopenharmony_ci#define FPSW_U (1<<1) 638c2ecf20Sopenharmony_ci#define FPSW_I (1<<0) 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci/* Handle a floating point exception. Return zero if the faulting 668c2ecf20Sopenharmony_ci instruction can be completed successfully. */ 678c2ecf20Sopenharmony_ciint 688c2ecf20Sopenharmony_cihandle_fpe(struct pt_regs *regs) 698c2ecf20Sopenharmony_ci{ 708c2ecf20Sopenharmony_ci extern void printbinary(unsigned long x, int nbits); 718c2ecf20Sopenharmony_ci unsigned int orig_sw, sw; 728c2ecf20Sopenharmony_ci int signalcode; 738c2ecf20Sopenharmony_ci /* need an intermediate copy of float regs because FPU emulation 748c2ecf20Sopenharmony_ci * code expects an artificial last entry which contains zero 758c2ecf20Sopenharmony_ci * 768c2ecf20Sopenharmony_ci * also, the passed in fr registers contain one word that defines 778c2ecf20Sopenharmony_ci * the fpu type. the fpu type information is constructed 788c2ecf20Sopenharmony_ci * inside the emulation code 798c2ecf20Sopenharmony_ci */ 808c2ecf20Sopenharmony_ci __u64 frcopy[36]; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci memcpy(frcopy, regs->fr, sizeof regs->fr); 838c2ecf20Sopenharmony_ci frcopy[32] = 0; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci memcpy(&orig_sw, frcopy, sizeof(orig_sw)); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci if (FPUDEBUG) { 888c2ecf20Sopenharmony_ci printk(KERN_DEBUG "FP VZOUICxxxxCQCQCQCQCQCRMxxTDVZOUI ->\n "); 898c2ecf20Sopenharmony_ci printbinary(orig_sw, 32); 908c2ecf20Sopenharmony_ci printk(KERN_DEBUG "\n"); 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci signalcode = decode_fpu(frcopy, 0x666); 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci /* Status word = FR0L. */ 968c2ecf20Sopenharmony_ci memcpy(&sw, frcopy, sizeof(sw)); 978c2ecf20Sopenharmony_ci if (FPUDEBUG) { 988c2ecf20Sopenharmony_ci printk(KERN_DEBUG "VZOUICxxxxCQCQCQCQCQCRMxxTDVZOUI decode_fpu returns %d|0x%x\n", 998c2ecf20Sopenharmony_ci signalcode >> 24, signalcode & 0xffffff); 1008c2ecf20Sopenharmony_ci printbinary(sw, 32); 1018c2ecf20Sopenharmony_ci printk(KERN_DEBUG "\n"); 1028c2ecf20Sopenharmony_ci } 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci memcpy(regs->fr, frcopy, sizeof regs->fr); 1058c2ecf20Sopenharmony_ci if (signalcode != 0) { 1068c2ecf20Sopenharmony_ci force_sig_fault(signalcode >> 24, signalcode & 0xffffff, 1078c2ecf20Sopenharmony_ci (void __user *) regs->iaoq[0]); 1088c2ecf20Sopenharmony_ci return -1; 1098c2ecf20Sopenharmony_ci } 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci return signalcode ? -1 : 0; 1128c2ecf20Sopenharmony_ci} 113