]>
Commit | Line | Data |
---|---|---|
b2441318 | 1 | // SPDX-License-Identifier: GPL-2.0 |
67207b96 AB |
2 | #include <linux/file.h> |
3 | #include <linux/fs.h> | |
4b16f8e2 | 4 | #include <linux/export.h> |
67207b96 AB |
5 | #include <linux/mount.h> |
6 | #include <linux/namei.h> | |
5a0e3ad6 | 7 | #include <linux/slab.h> |
67207b96 | 8 | |
7c0f6ba6 | 9 | #include <linux/uaccess.h> |
67207b96 AB |
10 | |
11 | #include "spufs.h" | |
12 | ||
13 | /** | |
14 | * sys_spu_run - run code loaded into an SPU | |
15 | * | |
16 | * @unpc: next program counter for the SPU | |
17 | * @ustatus: status of the SPU | |
18 | * | |
19 | * This system call transfers the control of execution of a | |
20 | * user space thread to an SPU. It will return when the | |
21 | * SPU has finished executing or when it hits an error | |
22 | * condition and it will be interrupted if a signal needs | |
23 | * to be delivered to a handler in user space. | |
24 | * | |
25 | * The next program counter is set to the passed value | |
26 | * before the SPU starts fetching code and the user space | |
27 | * pointer gets updated with the new value when returning | |
28 | * from kernel space. | |
29 | * | |
30 | * The status value returned from spu_run reflects the | |
31 | * value of the spu_status register after the SPU has stopped. | |
32 | * | |
33 | */ | |
8fce10a3 AB |
34 | static long do_spu_run(struct file *filp, |
35 | __u32 __user *unpc, | |
36 | __u32 __user *ustatus) | |
67207b96 AB |
37 | { |
38 | long ret; | |
39 | struct spufs_inode_info *i; | |
40 | u32 npc, status; | |
41 | ||
42 | ret = -EFAULT; | |
9add11da | 43 | if (get_user(npc, unpc)) |
67207b96 AB |
44 | goto out; |
45 | ||
e80358ad | 46 | /* check if this file was created by spu_create */ |
67207b96 | 47 | ret = -EINVAL; |
e80358ad | 48 | if (filp->f_op != &spufs_context_fops) |
67207b96 AB |
49 | goto out; |
50 | ||
496ad9aa | 51 | i = SPUFS_I(file_inode(filp)); |
50af32a9 | 52 | ret = spufs_run_spu(i->i_ctx, &npc, &status); |
67207b96 | 53 | |
9add11da AB |
54 | if (put_user(npc, unpc)) |
55 | ret = -EFAULT; | |
56 | ||
57 | if (ustatus && put_user(status, ustatus)) | |
67207b96 AB |
58 | ret = -EFAULT; |
59 | out: | |
60 | return ret; | |
61 | } | |
62 | ||
1e8b0f6d | 63 | static long do_spu_create(const char __user *pathname, unsigned int flags, |
c6684b26 | 64 | umode_t mode, struct file *neighbor) |
67207b96 | 65 | { |
1ba10681 AV |
66 | struct path path; |
67 | struct dentry *dentry; | |
67207b96 AB |
68 | int ret; |
69 | ||
1ac12b4b | 70 | dentry = user_path_create(AT_FDCWD, pathname, &path, LOOKUP_DIRECTORY); |
1ba10681 AV |
71 | ret = PTR_ERR(dentry); |
72 | if (!IS_ERR(dentry)) { | |
73 | ret = spufs_create(&path, dentry, flags, mode, neighbor); | |
921a1650 | 74 | done_path_create(&path, dentry); |
67207b96 AB |
75 | } |
76 | ||
77 | return ret; | |
78 | } | |
79 | ||
80 | struct spufs_calls spufs_calls = { | |
8e68e2f2 | 81 | .create_thread = do_spu_create, |
67207b96 | 82 | .spu_run = do_spu_run, |
aed3a8c9 | 83 | .notify_spus_active = do_notify_spus_active, |
67207b96 | 84 | .owner = THIS_MODULE, |
e623fbf1 ME |
85 | #ifdef CONFIG_COREDUMP |
86 | .coredump_extra_notes_size = spufs_coredump_extra_notes_size, | |
87 | .coredump_extra_notes_write = spufs_coredump_extra_notes_write, | |
88 | #endif | |
67207b96 | 89 | }; |