Commit | Line | Data |
---|---|---|
660662f8 | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
1da177e4 LT |
2 | /* |
3 | * Linux/PA-RISC Project (http://www.parisc-linux.org/) | |
4 | * | |
5 | * Floating-point emulation code | |
6 | * Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org> | |
1da177e4 LT |
7 | */ |
8 | /* | |
9 | * linux/arch/math-emu/driver.c.c | |
10 | * | |
11 | * decodes and dispatches unimplemented FPU instructions | |
12 | * | |
13 | * Copyright (C) 1999, 2000 Philipp Rumpf <prumpf@tux.org> | |
14 | * Copyright (C) 2001 Hewlett-Packard <bame@debian.org> | |
15 | */ | |
16 | ||
3f07c014 IM |
17 | #include <linux/sched/signal.h> |
18 | ||
1da177e4 LT |
19 | #include "float.h" |
20 | #include "math-emu.h" | |
21 | ||
22 | ||
23 | #define fptpos 31 | |
24 | #define fpr1pos 10 | |
25 | #define extru(r,pos,len) (((r) >> (31-(pos))) & (( 1 << (len)) - 1)) | |
26 | ||
27 | #define FPUDEBUG 0 | |
28 | ||
1da177e4 LT |
29 | /* Macros for grabbing bits of the instruction format from the 'ei' |
30 | field above. */ | |
31 | /* Major opcode 0c and 0e */ | |
32 | #define FP0CE_UID(i) (((i) >> 6) & 3) | |
33 | #define FP0CE_CLASS(i) (((i) >> 9) & 3) | |
34 | #define FP0CE_SUBOP(i) (((i) >> 13) & 7) | |
35 | #define FP0CE_SUBOP1(i) (((i) >> 15) & 7) /* Class 1 subopcode */ | |
36 | #define FP0C_FORMAT(i) (((i) >> 11) & 3) | |
37 | #define FP0E_FORMAT(i) (((i) >> 11) & 1) | |
38 | ||
39 | /* Major opcode 0c, uid 2 (performance monitoring) */ | |
40 | #define FPPM_SUBOP(i) (((i) >> 9) & 0x1f) | |
41 | ||
42 | /* Major opcode 2e (fused operations). */ | |
43 | #define FP2E_SUBOP(i) (((i) >> 5) & 1) | |
44 | #define FP2E_FORMAT(i) (((i) >> 11) & 1) | |
45 | ||
46 | /* Major opcode 26 (FMPYSUB) */ | |
47 | /* Major opcode 06 (FMPYADD) */ | |
48 | #define FPx6_FORMAT(i) ((i) & 0x1f) | |
49 | ||
50 | /* Flags and enable bits of the status word. */ | |
51 | #define FPSW_FLAGS(w) ((w) >> 27) | |
52 | #define FPSW_ENABLE(w) ((w) & 0x1f) | |
53 | #define FPSW_V (1<<4) | |
54 | #define FPSW_Z (1<<3) | |
55 | #define FPSW_O (1<<2) | |
56 | #define FPSW_U (1<<1) | |
57 | #define FPSW_I (1<<0) | |
58 | ||
59 | /* Handle a floating point exception. Return zero if the faulting | |
60 | instruction can be completed successfully. */ | |
61 | int | |
62 | handle_fpe(struct pt_regs *regs) | |
63 | { | |
64 | extern void printbinary(unsigned long x, int nbits); | |
1da177e4 LT |
65 | unsigned int orig_sw, sw; |
66 | int signalcode; | |
67 | /* need an intermediate copy of float regs because FPU emulation | |
68 | * code expects an artificial last entry which contains zero | |
69 | * | |
70 | * also, the passed in fr registers contain one word that defines | |
71 | * the fpu type. the fpu type information is constructed | |
72 | * inside the emulation code | |
73 | */ | |
74 | __u64 frcopy[36]; | |
75 | ||
76 | memcpy(frcopy, regs->fr, sizeof regs->fr); | |
77 | frcopy[32] = 0; | |
78 | ||
79 | memcpy(&orig_sw, frcopy, sizeof(orig_sw)); | |
80 | ||
81 | if (FPUDEBUG) { | |
82 | printk(KERN_DEBUG "FP VZOUICxxxxCQCQCQCQCQCRMxxTDVZOUI ->\n "); | |
83 | printbinary(orig_sw, 32); | |
84 | printk(KERN_DEBUG "\n"); | |
85 | } | |
86 | ||
87 | signalcode = decode_fpu(frcopy, 0x666); | |
88 | ||
89 | /* Status word = FR0L. */ | |
90 | memcpy(&sw, frcopy, sizeof(sw)); | |
91 | if (FPUDEBUG) { | |
92 | printk(KERN_DEBUG "VZOUICxxxxCQCQCQCQCQCRMxxTDVZOUI decode_fpu returns %d|0x%x\n", | |
93 | signalcode >> 24, signalcode & 0xffffff); | |
94 | printbinary(sw, 32); | |
95 | printk(KERN_DEBUG "\n"); | |
96 | } | |
97 | ||
98 | memcpy(regs->fr, frcopy, sizeof regs->fr); | |
99 | if (signalcode != 0) { | |
ccf75290 | 100 | force_sig_fault(signalcode >> 24, signalcode & 0xffffff, |
2e1661d2 | 101 | (void __user *) regs->iaoq[0]); |
1da177e4 LT |
102 | return -1; |
103 | } | |
104 | ||
105 | return signalcode ? -1 : 0; | |
106 | } |