// SPDX-License-Identifier: GPL-2.0-or-later1/*2* Linux/PA-RISC Project (http://www.parisc-linux.org/)3*4* Floating-point emulation code5* Copyright (C) 2001 Hewlett-Packard (Paul Bame) <[email protected]>6*/7/*8* linux/arch/math-emu/driver.c.c9*10* decodes and dispatches unimplemented FPU instructions11*12* Copyright (C) 1999, 2000 Philipp Rumpf <[email protected]>13* Copyright (C) 2001 Hewlett-Packard <[email protected]>14*/1516#include <linux/sched/signal.h>1718#include "float.h"19#include "math-emu.h"202122#define fptpos 3123#define fpr1pos 1024#define extru(r,pos,len) (((r) >> (31-(pos))) & (( 1 << (len)) - 1))2526#define FPUDEBUG 02728/* Macros for grabbing bits of the instruction format from the 'ei'29field above. */30/* Major opcode 0c and 0e */31#define FP0CE_UID(i) (((i) >> 6) & 3)32#define FP0CE_CLASS(i) (((i) >> 9) & 3)33#define FP0CE_SUBOP(i) (((i) >> 13) & 7)34#define FP0CE_SUBOP1(i) (((i) >> 15) & 7) /* Class 1 subopcode */35#define FP0C_FORMAT(i) (((i) >> 11) & 3)36#define FP0E_FORMAT(i) (((i) >> 11) & 1)3738/* Major opcode 0c, uid 2 (performance monitoring) */39#define FPPM_SUBOP(i) (((i) >> 9) & 0x1f)4041/* Major opcode 2e (fused operations). */42#define FP2E_SUBOP(i) (((i) >> 5) & 1)43#define FP2E_FORMAT(i) (((i) >> 11) & 1)4445/* Major opcode 26 (FMPYSUB) */46/* Major opcode 06 (FMPYADD) */47#define FPx6_FORMAT(i) ((i) & 0x1f)4849/* Flags and enable bits of the status word. */50#define FPSW_FLAGS(w) ((w) >> 27)51#define FPSW_ENABLE(w) ((w) & 0x1f)52#define FPSW_V (1<<4)53#define FPSW_Z (1<<3)54#define FPSW_O (1<<2)55#define FPSW_U (1<<1)56#define FPSW_I (1<<0)5758/* Handle a floating point exception. Return zero if the faulting59instruction can be completed successfully. */60int61handle_fpe(struct pt_regs *regs)62{63extern void printbinary(unsigned long x, int nbits);64unsigned int orig_sw, sw;65int signalcode;66/* need an intermediate copy of float regs because FPU emulation67* code expects an artificial last entry which contains zero68*69* also, the passed in fr registers contain one word that defines70* the fpu type. the fpu type information is constructed71* inside the emulation code72*/73__u64 frcopy[36];7475memcpy(frcopy, regs->fr, sizeof regs->fr);76frcopy[32] = 0;7778memcpy(&orig_sw, frcopy, sizeof(orig_sw));7980if (FPUDEBUG) {81printk(KERN_DEBUG "FP VZOUICxxxxCQCQCQCQCQCRMxxTDVZOUI ->\n ");82printbinary(orig_sw, 32);83printk(KERN_DEBUG "\n");84}8586signalcode = decode_fpu(frcopy, 0x666);8788/* Status word = FR0L. */89memcpy(&sw, frcopy, sizeof(sw));90if (FPUDEBUG) {91printk(KERN_DEBUG "VZOUICxxxxCQCQCQCQCQCRMxxTDVZOUI decode_fpu returns %d|0x%x\n",92signalcode >> 24, signalcode & 0xffffff);93printbinary(sw, 32);94printk(KERN_DEBUG "\n");95}9697memcpy(regs->fr, frcopy, sizeof regs->fr);98if (signalcode != 0) {99int sig = signalcode >> 24;100101if (sig == SIGFPE) {102/*103* Clear floating point trap bit to avoid trapping104* again on the first floating-point instruction in105* the userspace signal handler.106*/107regs->fr[0] &= ~(1ULL << 38);108}109force_sig_fault(sig, signalcode & 0xffffff,110(void __user *) regs->iaoq[0]);111return -1;112}113114return signalcode ? -1 : 0;115}116117118