Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/mn10300/kernel/fpu.c
10817 views
1
/* MN10300 FPU management
2
*
3
* Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4
* Written by David Howells ([email protected])
5
*
6
* This program is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU General Public Licence
8
* as published by the Free Software Foundation; either version
9
* 2 of the Licence, or (at your option) any later version.
10
*/
11
#include <asm/uaccess.h>
12
#include <asm/fpu.h>
13
#include <asm/elf.h>
14
#include <asm/exceptions.h>
15
#include <asm/system.h>
16
17
#ifdef CONFIG_LAZY_SAVE_FPU
18
struct task_struct *fpu_state_owner;
19
#endif
20
21
/*
22
* error functions in FPU disabled exception
23
*/
24
asmlinkage void fpu_disabled_in_kernel(struct pt_regs *regs)
25
{
26
die_if_no_fixup("An FPU Disabled exception happened in kernel space\n",
27
regs, EXCEP_FPU_DISABLED);
28
}
29
30
/*
31
* handle an FPU operational exception
32
* - there's a possibility that if the FPU is asynchronous, the signal might
33
* be meant for a process other than the current one
34
*/
35
asmlinkage void fpu_exception(struct pt_regs *regs, enum exception_code code)
36
{
37
struct task_struct *tsk = current;
38
siginfo_t info;
39
u32 fpcr;
40
41
if (!user_mode(regs))
42
die_if_no_fixup("An FPU Operation exception happened in"
43
" kernel space\n",
44
regs, code);
45
46
if (!is_using_fpu(tsk))
47
die_if_no_fixup("An FPU Operation exception happened,"
48
" but the FPU is not in use",
49
regs, code);
50
51
info.si_signo = SIGFPE;
52
info.si_errno = 0;
53
info.si_addr = (void *) tsk->thread.uregs->pc;
54
info.si_code = FPE_FLTINV;
55
56
unlazy_fpu(tsk);
57
58
fpcr = tsk->thread.fpu_state.fpcr;
59
60
if (fpcr & FPCR_EC_Z)
61
info.si_code = FPE_FLTDIV;
62
else if (fpcr & FPCR_EC_O)
63
info.si_code = FPE_FLTOVF;
64
else if (fpcr & FPCR_EC_U)
65
info.si_code = FPE_FLTUND;
66
else if (fpcr & FPCR_EC_I)
67
info.si_code = FPE_FLTRES;
68
69
force_sig_info(SIGFPE, &info, tsk);
70
}
71
72
/*
73
* save the FPU state to a signal context
74
*/
75
int fpu_setup_sigcontext(struct fpucontext *fpucontext)
76
{
77
struct task_struct *tsk = current;
78
79
if (!is_using_fpu(tsk))
80
return 0;
81
82
/* transfer the current FPU state to memory and cause fpu_init() to be
83
* triggered by the next attempted FPU operation by the current
84
* process.
85
*/
86
preempt_disable();
87
88
#ifndef CONFIG_LAZY_SAVE_FPU
89
if (tsk->thread.fpu_flags & THREAD_HAS_FPU) {
90
fpu_save(&tsk->thread.fpu_state);
91
tsk->thread.uregs->epsw &= ~EPSW_FE;
92
tsk->thread.fpu_flags &= ~THREAD_HAS_FPU;
93
}
94
#else /* !CONFIG_LAZY_SAVE_FPU */
95
if (fpu_state_owner == tsk) {
96
fpu_save(&tsk->thread.fpu_state);
97
fpu_state_owner->thread.uregs->epsw &= ~EPSW_FE;
98
fpu_state_owner = NULL;
99
}
100
#endif /* !CONFIG_LAZY_SAVE_FPU */
101
102
preempt_enable();
103
104
/* we no longer have a valid current FPU state */
105
clear_using_fpu(tsk);
106
107
/* transfer the saved FPU state onto the userspace stack */
108
if (copy_to_user(fpucontext,
109
&tsk->thread.fpu_state,
110
min(sizeof(struct fpu_state_struct),
111
sizeof(struct fpucontext))))
112
return -1;
113
114
return 1;
115
}
116
117
/*
118
* kill a process's FPU state during restoration after signal handling
119
*/
120
void fpu_kill_state(struct task_struct *tsk)
121
{
122
/* disown anything left in the FPU */
123
preempt_disable();
124
125
#ifndef CONFIG_LAZY_SAVE_FPU
126
if (tsk->thread.fpu_flags & THREAD_HAS_FPU) {
127
tsk->thread.uregs->epsw &= ~EPSW_FE;
128
tsk->thread.fpu_flags &= ~THREAD_HAS_FPU;
129
}
130
#else /* !CONFIG_LAZY_SAVE_FPU */
131
if (fpu_state_owner == tsk) {
132
fpu_state_owner->thread.uregs->epsw &= ~EPSW_FE;
133
fpu_state_owner = NULL;
134
}
135
#endif /* !CONFIG_LAZY_SAVE_FPU */
136
137
preempt_enable();
138
139
/* we no longer have a valid current FPU state */
140
clear_using_fpu(tsk);
141
}
142
143
/*
144
* restore the FPU state from a signal context
145
*/
146
int fpu_restore_sigcontext(struct fpucontext *fpucontext)
147
{
148
struct task_struct *tsk = current;
149
int ret;
150
151
/* load up the old FPU state */
152
ret = copy_from_user(&tsk->thread.fpu_state, fpucontext,
153
min(sizeof(struct fpu_state_struct),
154
sizeof(struct fpucontext)));
155
if (!ret)
156
set_using_fpu(tsk);
157
158
return ret;
159
}
160
161
/*
162
* fill in the FPU structure for a core dump
163
*/
164
int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpreg)
165
{
166
struct task_struct *tsk = current;
167
int fpvalid;
168
169
fpvalid = is_using_fpu(tsk);
170
if (fpvalid) {
171
unlazy_fpu(tsk);
172
memcpy(fpreg, &tsk->thread.fpu_state, sizeof(*fpreg));
173
}
174
175
return fpvalid;
176
}
177
178