1 | // SPDX-License-Identifier: GPL-2.0 |
2 | #include <linux/file.h> |
3 | #include <linux/fs.h> |
4 | #include <linux/export.h> |
5 | #include <linux/mount.h> |
6 | #include <linux/namei.h> |
7 | #include <linux/slab.h> |
8 | |
9 | #include <linux/uaccess.h> |
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 | */ |
34 | static long do_spu_run(struct file *filp, |
35 | __u32 __user *unpc, |
36 | __u32 __user *ustatus) |
37 | { |
38 | long ret; |
39 | struct spufs_inode_info *i; |
40 | u32 npc, status; |
41 | |
42 | ret = -EFAULT; |
43 | if (get_user(npc, unpc)) |
44 | goto out; |
45 | |
46 | /* check if this file was created by spu_create */ |
47 | ret = -EINVAL; |
48 | if (filp->f_op != &spufs_context_fops) |
49 | goto out; |
50 | |
51 | i = SPUFS_I(file_inode(filp)); |
52 | ret = spufs_run_spu(ctx: i->i_ctx, npc: &npc, status: &status); |
53 | |
54 | if (put_user(npc, unpc)) |
55 | ret = -EFAULT; |
56 | |
57 | if (ustatus && put_user(status, ustatus)) |
58 | ret = -EFAULT; |
59 | out: |
60 | return ret; |
61 | } |
62 | |
63 | static long do_spu_create(const char __user *pathname, unsigned int flags, |
64 | umode_t mode, struct file *neighbor) |
65 | { |
66 | struct path path; |
67 | struct dentry *dentry; |
68 | int ret; |
69 | |
70 | dentry = user_path_create(AT_FDCWD, pathname, &path, LOOKUP_DIRECTORY); |
71 | ret = PTR_ERR(ptr: dentry); |
72 | if (!IS_ERR(ptr: dentry)) { |
73 | ret = spufs_create(nd: &path, dentry, flags, mode, filp: neighbor); |
74 | done_path_create(&path, dentry); |
75 | } |
76 | |
77 | return ret; |
78 | } |
79 | |
80 | struct spufs_calls spufs_calls = { |
81 | .create_thread = do_spu_create, |
82 | .spu_run = do_spu_run, |
83 | .notify_spus_active = do_notify_spus_active, |
84 | .owner = THIS_MODULE, |
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 |
89 | }; |
90 | |