1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
|
/*
* arch/mips/kernel/scall_o32.S
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 1997, 1998 by Ralf Baechle
*
* $Id: scall_o32.S,v 1.3 1998/03/26 07:39:10 ralf Exp $
*/
#include <asm/asm.h>
#include <linux/errno.h>
#include <asm/current.h>
#include <asm/mipsregs.h>
#include <asm/regdef.h>
#include <asm/stackframe.h>
#include <asm/unistd.h>
/* This duplicates the definition from <linux/sched.h> */
#define PF_TRACESYS 0x00000020 /* tracing system calls */
/* This duplicates the definition from <asm/signal.h> */
#define SIGILL 4 /* Illegal instruction (ANSI). */
/* Highest syscall used of any syscall flavour */
#define MAX_SYSCALL_NO __NR_Linux + __NR_Linux_syscalls
.align 5
NESTED(handle_sys, PT_SIZE, sp)
.set noat
SAVE_SOME
STI
.set at
lw t1, PT_EPC(sp) # skip syscall on return
sltiu t0, v0, MAX_SYSCALL_NO + 1 # check syscall number
addiu t1, 4 # skip to next instruction
beqz t0, illegal_syscall
sw t1, PT_EPC(sp)
/* XXX Put both in one cacheline, should save a bit. */
sll t0, v0, 2
lw t2, sys_call_table(t0) # syscall routine
lbu t3, sys_narg_table(v0) # number of arguments
beqz t2, illegal_syscall;
subu t0, t3, 5 # 5 or more arguments?
bgez t0, stackargs
stack_done:
lw t0, TASK_FLAGS($28) # syscall tracing enabled?
andi t0, PF_TRACESYS
bnez t0, trace_a_syscall
jalr t2 # Do The Real Thing (TM)
li t0, -EMAXERRNO - 1 # error?
sltu t0, t0, v0
sw t0, PT_R7(sp) # set error flag
beqz t0, 1f
negu v0 # error
sw v0, PT_R0(sp) # set flag for syscall restarting
1: sw v0, PT_R2(sp) # result
EXPORT(o32_ret_from_sys_call)
lw t0,bh_mask
lw t1,bh_active # unused delay slot
and t0,t1
bnez t0,o32_handle_bottom_half
9: lw t0,PT_STATUS(sp) # returning to kernel mode?
andi t1, t0, 0x10
lw t2, need_resched
beqz t1, o32_return # -> yes
bnez t2, o32_reschedule
lw v0, TASK_SIGPENDING($28)
move a0, zero
beqz v0, o32_return
move a1, sp
SAVE_STATIC
jal do_signal
o32_return:
RESTORE_SOME
RESTORE_SP
.set mips3
eret
.set mips0
o32_handle_bottom_half:
jal do_bottom_half
b 9b
o32_reschedule:
SAVE_STATIC
jal schedule
b o32_ret_from_sys_call
/* ------------------------------------------------------------------------ */
trace_a_syscall:
SAVE_STATIC
sw t2,PT_R1(sp)
jal syscall_trace
sw t2,PT_R1(sp)
jalr t2 # Do The Real Thing (TM)
li t0, -EMAXERRNO - 1 # error?
sltu t0, t0, v0
sw t0, PT_R7(sp) # set error flag
beqz t0, 1f
negu v0 # error
sw v0, PT_R0(sp) # set flag for syscall restarting
1: sw v0, PT_R2(sp) # result
jal syscall_trace
j ret_from_sys_call
/* ------------------------------------------------------------------------ */
/*
* More than four arguments. Try to deal with it by copying the
* stack arguments from the user stack to the kernel stack.
* This Sucks (TM).
*/
stackargs:
lw t0, PT_R29(sp) # get old user stack pointer
subu t3, 4
sll t1, t3, 2 # stack valid?
addu t1, t0 # end address
or t0, t1
bltz t0, bad_stack # -> sp is bad
lw t0, PT_R29(sp) # get old user stack pointer
la t1, 3f # copy 1 to 2 arguments
sll t3, t3, 3
subu t1, t3
jr t1
/* Ok, copy the args from the luser stack to the kernel stack */
1: lw t1, 20(t0) # argument #6 from usp
sw t1, 20(sp)
2: lw t1, 16(t0) # argument #5 from usp
sw t1, 16(sp)
3: j stack_done # go back
.section __ex_table,"a"
PTR 1b,bad_stack
PTR 2b,bad_stack
.previous
/*
* The stackpointer for a call with more than 4 arguments is bad.
*/
bad_stack:
negu v0 # error
sw v0, PT_R0(sp)
sw v0, PT_R2(sp)
li t0, 1 # set error flag
sw t0, PT_R7(sp)
j ret_from_sys_call
/*
* The system call does not exist in this kernel
*/
illegal_syscall:
li v0, ENOSYS # error
sw v0, PT_R2(sp)
li t0, 1 # set error flag
sw t0, PT_R7(sp)
j ret_from_sys_call
|