aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
authorArnd Bergmann <abergman@de.ibm.com>2006-03-22 18:00:09 -0500
committerPaul Mackerras <paulus@samba.org>2006-03-26 22:48:24 -0500
commit2dd14934c9138c562d93c501e88c6d6f061eb8ba (patch)
tree2eda4f517dd319989908a80bfbe06ce629932f77 /arch/powerpc
parenta7f31841a40776605c834053ad1eb82d539bd79f (diff)
[PATCH] spufs: allow SPU code to do syscalls
An SPU does not have a way to implement system calls itself, but it can create intercepts to the kernel. This patch uses the method defined by the JSRE interface for C99 host library calls from an SPU to implement Linux system calls. It uses the reserved SPU stop code 0x2104 for this, using the structure layout and syscall numbers for ppc64-linux. I'm still undecided wether it is better to have a list of allowed syscalls or a list of forbidden syscalls, since we can't allow an SPU to call all syscalls that are defined for ppc64-linux. This patch implements the easier choice of them, with a blacklist that only prevents an SPU from calling anything that interacts with its own execution, e.g fork, execve, clone, vfork, exit, spu_run and spu_create and everything that deals with signals. Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/platforms/cell/Makefile10
-rw-r--r--arch/powerpc/platforms/cell/spu_callbacks.c345
-rw-r--r--arch/powerpc/platforms/cell/spufs/run.c91
3 files changed, 444 insertions, 2 deletions
diff --git a/arch/powerpc/platforms/cell/Makefile b/arch/powerpc/platforms/cell/Makefile
index 3b998a393e3f..e570bad06394 100644
--- a/arch/powerpc/platforms/cell/Makefile
+++ b/arch/powerpc/platforms/cell/Makefile
@@ -6,5 +6,11 @@ obj-$(CONFIG_SPU_FS) += spu-base.o spufs/
6 6
7spu-base-y += spu_base.o spu_priv1.o 7spu-base-y += spu_base.o spu_priv1.o
8 8
9builtin-spufs-$(CONFIG_SPU_FS) += spu_syscalls.o 9# needed only when building loadable spufs.ko
10obj-y += $(builtin-spufs-m) 10spufs-modular-$(CONFIG_SPU_FS) += spu_syscalls.o
11obj-y += $(spufs-modular-m)
12
13# always needed in kernel
14spufs-builtin-$(CONFIG_SPU_FS) += spu_callbacks.o
15obj-y += $(spufs-builtin-y) $(spufs-builtin-m)
16
diff --git a/arch/powerpc/platforms/cell/spu_callbacks.c b/arch/powerpc/platforms/cell/spu_callbacks.c
new file mode 100644
index 000000000000..3a4245c926ad
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spu_callbacks.c
@@ -0,0 +1,345 @@
1/*
2 * System call callback functions for SPUs
3 */
4
5#define DEBUG
6
7#include <linux/kallsyms.h>
8#include <linux/module.h>
9#include <linux/syscalls.h>
10
11#include <asm/spu.h>
12#include <asm/syscalls.h>
13#include <asm/unistd.h>
14
15/*
16 * This table defines the system calls that an SPU can call.
17 * It is currently a subset of the 64 bit powerpc system calls,
18 * with the exact semantics.
19 *
20 * The reasons for disabling some of the system calls are:
21 * 1. They interact with the way SPU syscalls are handled
22 * and we can't let them execute ever:
23 * restart_syscall, exit, for, execve, ptrace, ...
24 * 2. They are deprecated and replaced by other means:
25 * uselib, pciconfig_*, sysfs, ...
26 * 3. They are somewhat interacting with the system in a way
27 * we don't want an SPU to:
28 * reboot, init_module, mount, kexec_load
29 * 4. They are optional and we can't rely on them being
30 * linked into the kernel. Unfortunately, the cond_syscall
31 * helper does not work here as it does not add the necessary
32 * opd symbols:
33 * mbind, mq_open, ipc, ...
34 */
35
36void *spu_syscall_table[] = {
37 [__NR_restart_syscall] sys_ni_syscall, /* sys_restart_syscall */
38 [__NR_exit] sys_ni_syscall, /* sys_exit */
39 [__NR_fork] sys_ni_syscall, /* ppc_fork */
40 [__NR_read] sys_read,
41 [__NR_write] sys_write,
42 [__NR_open] sys_open,
43 [__NR_close] sys_close,
44 [__NR_waitpid] sys_waitpid,
45 [__NR_creat] sys_creat,
46 [__NR_link] sys_link,
47 [__NR_unlink] sys_unlink,
48 [__NR_execve] sys_ni_syscall, /* sys_execve */
49 [__NR_chdir] sys_chdir,
50 [__NR_time] sys_time,
51 [__NR_mknod] sys_mknod,
52 [__NR_chmod] sys_chmod,
53 [__NR_lchown] sys_lchown,
54 [__NR_break] sys_ni_syscall,
55 [__NR_oldstat] sys_ni_syscall,
56 [__NR_lseek] sys_lseek,
57 [__NR_getpid] sys_getpid,
58 [__NR_mount] sys_ni_syscall, /* sys_mount */
59 [__NR_umount] sys_ni_syscall,
60 [__NR_setuid] sys_setuid,
61 [__NR_getuid] sys_getuid,
62 [__NR_stime] sys_stime,
63 [__NR_ptrace] sys_ni_syscall, /* sys_ptrace */
64 [__NR_alarm] sys_alarm,
65 [__NR_oldfstat] sys_ni_syscall,
66 [__NR_pause] sys_ni_syscall, /* sys_pause */
67 [__NR_utime] sys_ni_syscall, /* sys_utime */
68 [__NR_stty] sys_ni_syscall,
69 [__NR_gtty] sys_ni_syscall,
70 [__NR_access] sys_access,
71 [__NR_nice] sys_nice,
72 [__NR_ftime] sys_ni_syscall,
73 [__NR_sync] sys_sync,
74 [__NR_kill] sys_kill,
75 [__NR_rename] sys_rename,
76 [__NR_mkdir] sys_mkdir,
77 [__NR_rmdir] sys_rmdir,
78 [__NR_dup] sys_dup,
79 [__NR_pipe] sys_pipe,
80 [__NR_times] sys_times,
81 [__NR_prof] sys_ni_syscall,
82 [__NR_brk] sys_brk,
83 [__NR_setgid] sys_setgid,
84 [__NR_getgid] sys_getgid,
85 [__NR_signal] sys_ni_syscall, /* sys_signal */
86 [__NR_geteuid] sys_geteuid,
87 [__NR_getegid] sys_getegid,
88 [__NR_acct] sys_ni_syscall, /* sys_acct */
89 [__NR_umount2] sys_ni_syscall, /* sys_umount */
90 [__NR_lock] sys_ni_syscall,
91 [__NR_ioctl] sys_ioctl,
92 [__NR_fcntl] sys_fcntl,
93 [__NR_mpx] sys_ni_syscall,
94 [__NR_setpgid] sys_setpgid,
95 [__NR_ulimit] sys_ni_syscall,
96 [__NR_oldolduname] sys_ni_syscall,
97 [__NR_umask] sys_umask,
98 [__NR_chroot] sys_chroot,
99 [__NR_ustat] sys_ni_syscall, /* sys_ustat */
100 [__NR_dup2] sys_dup2,
101 [__NR_getppid] sys_getppid,
102 [__NR_getpgrp] sys_getpgrp,
103 [__NR_setsid] sys_setsid,
104 [__NR_sigaction] sys_ni_syscall,
105 [__NR_sgetmask] sys_sgetmask,
106 [__NR_ssetmask] sys_ssetmask,
107 [__NR_setreuid] sys_setreuid,
108 [__NR_setregid] sys_setregid,
109 [__NR_sigsuspend] sys_ni_syscall,
110 [__NR_sigpending] sys_ni_syscall,
111 [__NR_sethostname] sys_sethostname,
112 [__NR_setrlimit] sys_setrlimit,
113 [__NR_getrlimit] sys_ni_syscall,
114 [__NR_getrusage] sys_getrusage,
115 [__NR_gettimeofday] sys_gettimeofday,
116 [__NR_settimeofday] sys_settimeofday,
117 [__NR_getgroups] sys_getgroups,
118 [__NR_setgroups] sys_setgroups,
119 [__NR_select] sys_ni_syscall,
120 [__NR_symlink] sys_symlink,
121 [__NR_oldlstat] sys_ni_syscall,
122 [__NR_readlink] sys_readlink,
123 [__NR_uselib] sys_ni_syscall, /* sys_uselib */
124 [__NR_swapon] sys_ni_syscall, /* sys_swapon */
125 [__NR_reboot] sys_ni_syscall, /* sys_reboot */
126 [__NR_readdir] sys_ni_syscall,
127 [__NR_mmap] sys_mmap,
128 [__NR_munmap] sys_munmap,
129 [__NR_truncate] sys_truncate,
130 [__NR_ftruncate] sys_ftruncate,
131 [__NR_fchmod] sys_fchmod,
132 [__NR_fchown] sys_fchown,
133 [__NR_getpriority] sys_getpriority,
134 [__NR_setpriority] sys_setpriority,
135 [__NR_profil] sys_ni_syscall,
136 [__NR_statfs] sys_ni_syscall, /* sys_statfs */
137 [__NR_fstatfs] sys_ni_syscall, /* sys_fstatfs */
138 [__NR_ioperm] sys_ni_syscall,
139 [__NR_socketcall] sys_socketcall,
140 [__NR_syslog] sys_syslog,
141 [__NR_setitimer] sys_setitimer,
142 [__NR_getitimer] sys_getitimer,
143 [__NR_stat] sys_newstat,
144 [__NR_lstat] sys_newlstat,
145 [__NR_fstat] sys_newfstat,
146 [__NR_olduname] sys_ni_syscall,
147 [__NR_iopl] sys_ni_syscall,
148 [__NR_vhangup] sys_vhangup,
149 [__NR_idle] sys_ni_syscall,
150 [__NR_vm86] sys_ni_syscall,
151 [__NR_wait4] sys_wait4,
152 [__NR_swapoff] sys_ni_syscall, /* sys_swapoff */
153 [__NR_sysinfo] sys_sysinfo,
154 [__NR_ipc] sys_ni_syscall, /* sys_ipc */
155 [__NR_fsync] sys_fsync,
156 [__NR_sigreturn] sys_ni_syscall,
157 [__NR_clone] sys_ni_syscall, /* ppc_clone */
158 [__NR_setdomainname] sys_setdomainname,
159 [__NR_uname] ppc_newuname,
160 [__NR_modify_ldt] sys_ni_syscall,
161 [__NR_adjtimex] sys_adjtimex,
162 [__NR_mprotect] sys_mprotect,
163 [__NR_sigprocmask] sys_ni_syscall,
164 [__NR_create_module] sys_ni_syscall,
165 [__NR_init_module] sys_ni_syscall, /* sys_init_module */
166 [__NR_delete_module] sys_ni_syscall, /* sys_delete_module */
167 [__NR_get_kernel_syms] sys_ni_syscall,
168 [__NR_quotactl] sys_ni_syscall, /* sys_quotactl */
169 [__NR_getpgid] sys_getpgid,
170 [__NR_fchdir] sys_fchdir,
171 [__NR_bdflush] sys_bdflush,
172 [__NR_sysfs] sys_ni_syscall, /* sys_sysfs */
173 [__NR_personality] ppc64_personality,
174 [__NR_afs_syscall] sys_ni_syscall,
175 [__NR_setfsuid] sys_setfsuid,
176 [__NR_setfsgid] sys_setfsgid,
177 [__NR__llseek] sys_llseek,
178 [__NR_getdents] sys_getdents,
179 [__NR__newselect] sys_select,
180 [__NR_flock] sys_flock,
181 [__NR_msync] sys_msync,
182 [__NR_readv] sys_readv,
183 [__NR_writev] sys_writev,
184 [__NR_getsid] sys_getsid,
185 [__NR_fdatasync] sys_fdatasync,
186 [__NR__sysctl] sys_ni_syscall, /* sys_sysctl */
187 [__NR_mlock] sys_mlock,
188 [__NR_munlock] sys_munlock,
189 [__NR_mlockall] sys_mlockall,
190 [__NR_munlockall] sys_munlockall,
191 [__NR_sched_setparam] sys_sched_setparam,
192 [__NR_sched_getparam] sys_sched_getparam,
193 [__NR_sched_setscheduler] sys_sched_setscheduler,
194 [__NR_sched_getscheduler] sys_sched_getscheduler,
195 [__NR_sched_yield] sys_sched_yield,
196 [__NR_sched_get_priority_max] sys_sched_get_priority_max,
197 [__NR_sched_get_priority_min] sys_sched_get_priority_min,
198 [__NR_sched_rr_get_interval] sys_sched_rr_get_interval,
199 [__NR_nanosleep] sys_nanosleep,
200 [__NR_mremap] sys_mremap,
201 [__NR_setresuid] sys_setresuid,
202 [__NR_getresuid] sys_getresuid,
203 [__NR_query_module] sys_ni_syscall,
204 [__NR_poll] sys_poll,
205 [__NR_nfsservctl] sys_ni_syscall, /* sys_nfsservctl */
206 [__NR_setresgid] sys_setresgid,
207 [__NR_getresgid] sys_getresgid,
208 [__NR_prctl] sys_prctl,
209 [__NR_rt_sigreturn] sys_ni_syscall, /* ppc64_rt_sigreturn */
210 [__NR_rt_sigaction] sys_ni_syscall, /* sys_rt_sigaction */
211 [__NR_rt_sigprocmask] sys_ni_syscall, /* sys_rt_sigprocmask */
212 [__NR_rt_sigpending] sys_ni_syscall, /* sys_rt_sigpending */
213 [__NR_rt_sigtimedwait] sys_ni_syscall, /* sys_rt_sigtimedwait */
214 [__NR_rt_sigqueueinfo] sys_ni_syscall, /* sys_rt_sigqueueinfo */
215 [__NR_rt_sigsuspend] sys_ni_syscall, /* sys_rt_sigsuspend */
216 [__NR_pread64] sys_pread64,
217 [__NR_pwrite64] sys_pwrite64,
218 [__NR_chown] sys_chown,
219 [__NR_getcwd] sys_getcwd,
220 [__NR_capget] sys_capget,
221 [__NR_capset] sys_capset,
222 [__NR_sigaltstack] sys_ni_syscall, /* sys_sigaltstack */
223 [__NR_sendfile] sys_sendfile64,
224 [__NR_getpmsg] sys_ni_syscall,
225 [__NR_putpmsg] sys_ni_syscall,
226 [__NR_vfork] sys_ni_syscall, /* ppc_vfork */
227 [__NR_ugetrlimit] sys_getrlimit,
228 [__NR_readahead] sys_readahead,
229 [192] sys_ni_syscall,
230 [193] sys_ni_syscall,
231 [194] sys_ni_syscall,
232 [195] sys_ni_syscall,
233 [196] sys_ni_syscall,
234 [197] sys_ni_syscall,
235 [__NR_pciconfig_read] sys_ni_syscall, /* sys_pciconfig_read */
236 [__NR_pciconfig_write] sys_ni_syscall, /* sys_pciconfig_write */
237 [__NR_pciconfig_iobase] sys_ni_syscall, /* sys_pciconfig_iobase */
238 [__NR_multiplexer] sys_ni_syscall,
239 [__NR_getdents64] sys_getdents64,
240 [__NR_pivot_root] sys_pivot_root,
241 [204] sys_ni_syscall,
242 [__NR_madvise] sys_madvise,
243 [__NR_mincore] sys_mincore,
244 [__NR_gettid] sys_gettid,
245 [__NR_tkill] sys_tkill,
246 [__NR_setxattr] sys_setxattr,
247 [__NR_lsetxattr] sys_lsetxattr,
248 [__NR_fsetxattr] sys_fsetxattr,
249 [__NR_getxattr] sys_getxattr,
250 [__NR_lgetxattr] sys_lgetxattr,
251 [__NR_fgetxattr] sys_fgetxattr,
252 [__NR_listxattr] sys_listxattr,
253 [__NR_llistxattr] sys_llistxattr,
254 [__NR_flistxattr] sys_flistxattr,
255 [__NR_removexattr] sys_removexattr,
256 [__NR_lremovexattr] sys_lremovexattr,
257 [__NR_fremovexattr] sys_fremovexattr,
258 [__NR_futex] sys_futex,
259 [__NR_sched_setaffinity] sys_sched_setaffinity,
260 [__NR_sched_getaffinity] sys_sched_getaffinity,
261 [__NR_tuxcall] sys_ni_syscall,
262 [226] sys_ni_syscall,
263 [__NR_io_setup] sys_io_setup,
264 [__NR_io_destroy] sys_io_destroy,
265 [__NR_io_getevents] sys_io_getevents,
266 [__NR_io_submit] sys_io_submit,
267 [__NR_io_cancel] sys_io_cancel,
268 [__NR_set_tid_address] sys_ni_syscall, /* sys_set_tid_address */
269 [__NR_fadvise64] sys_fadvise64,
270 [__NR_exit_group] sys_ni_syscall, /* sys_exit_group */
271 [__NR_lookup_dcookie] sys_ni_syscall, /* sys_lookup_dcookie */
272 [__NR_epoll_create] sys_epoll_create,
273 [__NR_epoll_ctl] sys_epoll_ctl,
274 [__NR_epoll_wait] sys_epoll_wait,
275 [__NR_remap_file_pages] sys_remap_file_pages,
276 [__NR_timer_create] sys_timer_create,
277 [__NR_timer_settime] sys_timer_settime,
278 [__NR_timer_gettime] sys_timer_gettime,
279 [__NR_timer_getoverrun] sys_timer_getoverrun,
280 [__NR_timer_delete] sys_timer_delete,
281 [__NR_clock_settime] sys_clock_settime,
282 [__NR_clock_gettime] sys_clock_gettime,
283 [__NR_clock_getres] sys_clock_getres,
284 [__NR_clock_nanosleep] sys_clock_nanosleep,
285 [__NR_swapcontext] sys_ni_syscall, /* ppc64_swapcontext */
286 [__NR_tgkill] sys_tgkill,
287 [__NR_utimes] sys_utimes,
288 [__NR_statfs64] sys_statfs64,
289 [__NR_fstatfs64] sys_fstatfs64,
290 [254] sys_ni_syscall,
291 [__NR_rtas] ppc_rtas,
292 [256] sys_ni_syscall,
293 [257] sys_ni_syscall,
294 [258] sys_ni_syscall,
295 [__NR_mbind] sys_ni_syscall, /* sys_mbind */
296 [__NR_get_mempolicy] sys_ni_syscall, /* sys_get_mempolicy */
297 [__NR_set_mempolicy] sys_ni_syscall, /* sys_set_mempolicy */
298 [__NR_mq_open] sys_ni_syscall, /* sys_mq_open */
299 [__NR_mq_unlink] sys_ni_syscall, /* sys_mq_unlink */
300 [__NR_mq_timedsend] sys_ni_syscall, /* sys_mq_timedsend */
301 [__NR_mq_timedreceive] sys_ni_syscall, /* sys_mq_timedreceive */
302 [__NR_mq_notify] sys_ni_syscall, /* sys_mq_notify */
303 [__NR_mq_getsetattr] sys_ni_syscall, /* sys_mq_getsetattr */
304 [__NR_kexec_load] sys_ni_syscall, /* sys_kexec_load */
305 [__NR_add_key] sys_ni_syscall, /* sys_add_key */
306 [__NR_request_key] sys_ni_syscall, /* sys_request_key */
307 [__NR_keyctl] sys_ni_syscall, /* sys_keyctl */
308 [__NR_waitid] sys_ni_syscall, /* sys_waitid */
309 [__NR_ioprio_set] sys_ni_syscall, /* sys_ioprio_set */
310 [__NR_ioprio_get] sys_ni_syscall, /* sys_ioprio_get */
311 [__NR_inotify_init] sys_ni_syscall, /* sys_inotify_init */
312 [__NR_inotify_add_watch] sys_ni_syscall, /* sys_inotify_add_watch */
313 [__NR_inotify_rm_watch] sys_ni_syscall, /* sys_inotify_rm_watch */
314 [__NR_spu_run] sys_ni_syscall, /* sys_spu_run */
315 [__NR_spu_create] sys_ni_syscall, /* sys_spu_create */
316 [__NR_pselect6] sys_ni_syscall, /* sys_pselect */
317 [__NR_ppoll] sys_ni_syscall, /* sys_ppoll */
318 [__NR_unshare] sys_unshare,
319};
320
321long spu_sys_callback(struct spu_syscall_block *s)
322{
323 long (*syscall)(u64 a1, u64 a2, u64 a3, u64 a4, u64 a5, u64 a6);
324
325 BUILD_BUG_ON(ARRAY_SIZE(spu_syscall_table) != __NR_syscalls);
326
327 syscall = spu_syscall_table[s->nr_ret];
328
329 if (s->nr_ret >= __NR_syscalls) {
330 pr_debug("%s: invalid syscall #%ld", __FUNCTION__, s->nr_ret);
331 return -ENOSYS;
332 }
333
334#ifdef DEBUG
335 print_symbol(KERN_DEBUG "SPU-syscall %s:", (unsigned long)syscall);
336 printk("syscall%ld(%lx, %lx, %lx, %lx, %lx, %lx)\n",
337 s->nr_ret,
338 s->parm[0], s->parm[1], s->parm[2],
339 s->parm[3], s->parm[4], s->parm[5]);
340#endif
341
342 return syscall(s->parm[0], s->parm[1], s->parm[2],
343 s->parm[3], s->parm[4], s->parm[5]);
344}
345EXPORT_SYMBOL_GPL(spu_sys_callback);
diff --git a/arch/powerpc/platforms/cell/spufs/run.c b/arch/powerpc/platforms/cell/spufs/run.c
index 18ea8866c61a..c04e078c0fe5 100644
--- a/arch/powerpc/platforms/cell/spufs/run.c
+++ b/arch/powerpc/platforms/cell/spufs/run.c
@@ -76,6 +76,90 @@ static inline int spu_reacquire_runnable(struct spu_context *ctx, u32 *npc,
76 return 0; 76 return 0;
77} 77}
78 78
79/*
80 * SPU syscall restarting is tricky because we violate the basic
81 * assumption that the signal handler is running on the interrupted
82 * thread. Here instead, the handler runs on PowerPC user space code,
83 * while the syscall was called from the SPU.
84 * This means we can only do a very rough approximation of POSIX
85 * signal semantics.
86 */
87int spu_handle_restartsys(struct spu_context *ctx, long *spu_ret,
88 unsigned int *npc)
89{
90 int ret;
91
92 switch (*spu_ret) {
93 case -ERESTARTSYS:
94 case -ERESTARTNOINTR:
95 /*
96 * Enter the regular syscall restarting for
97 * sys_spu_run, then restart the SPU syscall
98 * callback.
99 */
100 *npc -= 8;
101 ret = -ERESTARTSYS;
102 break;
103 case -ERESTARTNOHAND:
104 case -ERESTART_RESTARTBLOCK:
105 /*
106 * Restart block is too hard for now, just return -EINTR
107 * to the SPU.
108 * ERESTARTNOHAND comes from sys_pause, we also return
109 * -EINTR from there.
110 * Assume that we need to be restarted ourselves though.
111 */
112 *spu_ret = -EINTR;
113 ret = -ERESTARTSYS;
114 break;
115 default:
116 printk(KERN_WARNING "%s: unexpected return code %ld\n",
117 __FUNCTION__, *spu_ret);
118 ret = 0;
119 }
120 return ret;
121}
122
123int spu_process_callback(struct spu_context *ctx)
124{
125 struct spu_syscall_block s;
126 u32 ls_pointer, npc;
127 char *ls;
128 long spu_ret;
129 int ret;
130
131 /* get syscall block from local store */
132 npc = ctx->ops->npc_read(ctx);
133 ls = ctx->ops->get_ls(ctx);
134 ls_pointer = *(u32*)(ls + npc);
135 if (ls_pointer > (LS_SIZE - sizeof(s)))
136 return -EFAULT;
137 memcpy(&s, ls + ls_pointer, sizeof (s));
138
139 /* do actual syscall without pinning the spu */
140 ret = 0;
141 spu_ret = -ENOSYS;
142 npc += 4;
143
144 if (s.nr_ret < __NR_syscalls) {
145 spu_release(ctx);
146 /* do actual system call from here */
147 spu_ret = spu_sys_callback(&s);
148 if (spu_ret <= -ERESTARTSYS) {
149 ret = spu_handle_restartsys(ctx, &spu_ret, &npc);
150 }
151 spu_acquire(ctx);
152 if (ret == -ERESTARTSYS)
153 return ret;
154 }
155
156 /* write result, jump over indirect pointer */
157 memcpy(ls + ls_pointer, &spu_ret, sizeof (spu_ret));
158 ctx->ops->npc_write(ctx, npc);
159 ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE);
160 return ret;
161}
162
79static inline int spu_process_events(struct spu_context *ctx) 163static inline int spu_process_events(struct spu_context *ctx)
80{ 164{
81 struct spu *spu = ctx->spu; 165 struct spu *spu = ctx->spu;
@@ -107,6 +191,13 @@ long spufs_run_spu(struct file *file, struct spu_context *ctx,
107 ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, status)); 191 ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, status));
108 if (unlikely(ret)) 192 if (unlikely(ret))
109 break; 193 break;
194 if ((*status & SPU_STATUS_STOPPED_BY_STOP) &&
195 (*status >> SPU_STOP_STATUS_SHIFT == 0x2104)) {
196 ret = spu_process_callback(ctx);
197 if (ret)
198 break;
199 *status &= ~SPU_STATUS_STOPPED_BY_STOP;
200 }
110 if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) { 201 if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) {
111 ret = spu_reacquire_runnable(ctx, npc, status); 202 ret = spu_reacquire_runnable(ctx, npc, status);
112 if (ret) 203 if (ret)