Linux Kernel
3.7.1
Main Page
Related Pages
Modules
Namespaces
Data Structures
Files
File List
Globals
All
Data Structures
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
arch
mips
math-emu
dsemul.c
Go to the documentation of this file.
1
#include <linux/compiler.h>
2
#include <
linux/mm.h
>
3
#include <linux/signal.h>
4
#include <
linux/smp.h
>
5
6
#include <asm/asm.h>
7
#include <asm/bootinfo.h>
8
#include <asm/byteorder.h>
9
#include <asm/cpu.h>
10
#include <asm/inst.h>
11
#include <asm/processor.h>
12
#include <asm/uaccess.h>
13
#include <
asm/branch.h
>
14
#include <
asm/mipsregs.h
>
15
#include <asm/cacheflush.h>
16
17
#include <
asm/fpu_emulator.h
>
18
19
#include "
ieee754.h
"
20
21
/* Strap kernel emulator for full MIPS IV emulation */
22
23
#ifdef __mips
24
#undef __mips
25
#endif
26
#define __mips 4
27
28
/*
29
* Emulate the arbritrary instruction ir at xcp->cp0_epc. Required when
30
* we have to emulate the instruction in a COP1 branch delay slot. Do
31
* not change cp0_epc due to the instruction
32
*
33
* According to the spec:
34
* 1) it shouldn't be a branch :-)
35
* 2) it can be a COP instruction :-(
36
* 3) if we are tring to run a protected memory space we must take
37
* special care on memory access instructions :-(
38
*/
39
40
/*
41
* "Trampoline" return routine to catch exception following
42
* execution of delay-slot instruction execution.
43
*/
44
45
struct
emuframe
{
46
mips_instruction
emul
;
47
mips_instruction
badinst
;
48
mips_instruction
cookie
;
49
unsigned
long
epc
;
50
};
51
52
int
mips_dsemul
(
struct
pt_regs
*
regs
,
mips_instruction
ir
,
unsigned
long
cpc)
53
{
54
extern
asmlinkage
void
handle_dsemulret(
void
);
55
struct
emuframe
__user *fr;
56
int
err
;
57
58
if
(ir == 0) {
/* a nop is easy */
59
regs->
cp0_epc
= cpc;
60
regs->
cp0_cause
&= ~
CAUSEF_BD
;
61
return
0;
62
}
63
#ifdef DSEMUL_TRACE
64
printk
(
"dsemul %lx %lx\n"
, regs->
cp0_epc
, cpc);
65
66
#endif
67
68
/*
69
* The strategy is to push the instruction onto the user stack
70
* and put a trap after it which we can catch and jump to
71
* the required address any alternative apart from full
72
* instruction emulation!!.
73
*
74
* Algorithmics used a system call instruction, and
75
* borrowed that vector. MIPS/Linux version is a bit
76
* more heavyweight in the interests of portability and
77
* multiprocessor support. For Linux we generate a
78
* an unaligned access and force an address error exception.
79
*
80
* For embedded systems (stand-alone) we prefer to use a
81
* non-existing CP1 instruction. This prevents us from emulating
82
* branches, but gives us a cleaner interface to the exception
83
* handler (single entry point).
84
*/
85
86
/* Ensure that the two instructions are in the same cache line */
87
fr = (
struct
emuframe
__user *)
88
((regs->
regs
[29] -
sizeof
(
struct
emuframe
)) & ~0x7);
89
90
/* Verify that the stack pointer is not competely insane */
91
if
(
unlikely
(!
access_ok
(
VERIFY_WRITE
, fr,
sizeof
(
struct
emuframe
))))
92
return
SIGBUS
;
93
94
err =
__put_user
(ir, &fr->
emul
);
95
err |=
__put_user
((
mips_instruction
)
BREAK_MATH
, &fr->
badinst
);
96
err |=
__put_user
((
mips_instruction
)
BD_COOKIE
, &fr->
cookie
);
97
err |=
__put_user
(cpc, &fr->
epc
);
98
99
if
(
unlikely
(err)) {
100
MIPS_FPU_EMU_INC_STATS
(
errors
);
101
return
SIGBUS
;
102
}
103
104
regs->
cp0_epc
= (
unsigned
long
) &fr->
emul
;
105
106
flush_cache_sigtramp
((
unsigned
long
)&fr->
badinst
);
107
108
return
SIGILL
;
/* force out of emulation loop */
109
}
110
111
int
do_dsemulret
(
struct
pt_regs
*xcp)
112
{
113
struct
emuframe
__user *fr;
114
unsigned
long
epc
;
115
u32
insn
,
cookie
;
116
int
err
= 0;
117
118
fr = (
struct
emuframe
__user *)
119
(xcp->
cp0_epc
-
sizeof
(
mips_instruction
));
120
121
/*
122
* If we can't even access the area, something is very wrong, but we'll
123
* leave that to the default handling
124
*/
125
if
(!
access_ok
(
VERIFY_READ
, fr,
sizeof
(
struct
emuframe
)))
126
return
0;
127
128
/*
129
* Do some sanity checking on the stackframe:
130
*
131
* - Is the instruction pointed to by the EPC an BREAK_MATH?
132
* - Is the following memory word the BD_COOKIE?
133
*/
134
err =
__get_user
(insn, &fr->
badinst
);
135
err |=
__get_user
(cookie, &fr->
cookie
);
136
137
if
(
unlikely
(err || (insn !=
BREAK_MATH
) || (cookie !=
BD_COOKIE
))) {
138
MIPS_FPU_EMU_INC_STATS
(
errors
);
139
return
0;
140
}
141
142
/*
143
* At this point, we are satisfied that it's a BD emulation trap. Yes,
144
* a user might have deliberately put two malformed and useless
145
* instructions in a row in his program, in which case he's in for a
146
* nasty surprise - the next instruction will be treated as a
147
* continuation address! Alas, this seems to be the only way that we
148
* can handle signals, recursion, and longjmps() in the context of
149
* emulating the branch delay instruction.
150
*/
151
152
#ifdef DSEMUL_TRACE
153
printk
(
"dsemulret\n"
);
154
#endif
155
if
(
__get_user
(epc, &fr->
epc
)) {
/* Saved EPC */
156
/* This is not a good situation to be in */
157
force_sig
(
SIGBUS
,
current
);
158
159
return
0;
160
}
161
162
/* Set EPC to return to post-branch instruction */
163
xcp->
cp0_epc
=
epc
;
164
165
return
1;
166
}
Generated on Thu Jan 10 2013 13:11:39 for Linux Kernel by
1.8.2