|  | // SPDX-License-Identifier: GPL-2.0 | 
|  | #include <linux/file.h> | 
|  | #include <linux/fs.h> | 
|  | #include <linux/export.h> | 
|  | #include <linux/mount.h> | 
|  | #include <linux/namei.h> | 
|  | #include <linux/slab.h> | 
|  |  | 
|  | #include <linux/uaccess.h> | 
|  |  | 
|  | #include "spufs.h" | 
|  |  | 
|  | /** | 
|  | * sys_spu_run - run code loaded into an SPU | 
|  | * | 
|  | * @unpc:    next program counter for the SPU | 
|  | * @ustatus: status of the SPU | 
|  | * | 
|  | * This system call transfers the control of execution of a | 
|  | * user space thread to an SPU. It will return when the | 
|  | * SPU has finished executing or when it hits an error | 
|  | * condition and it will be interrupted if a signal needs | 
|  | * to be delivered to a handler in user space. | 
|  | * | 
|  | * The next program counter is set to the passed value | 
|  | * before the SPU starts fetching code and the user space | 
|  | * pointer gets updated with the new value when returning | 
|  | * from kernel space. | 
|  | * | 
|  | * The status value returned from spu_run reflects the | 
|  | * value of the spu_status register after the SPU has stopped. | 
|  | * | 
|  | */ | 
|  | static long do_spu_run(struct file *filp, | 
|  | __u32 __user *unpc, | 
|  | __u32 __user *ustatus) | 
|  | { | 
|  | long ret; | 
|  | struct spufs_inode_info *i; | 
|  | u32 npc, status; | 
|  |  | 
|  | ret = -EFAULT; | 
|  | if (get_user(npc, unpc)) | 
|  | goto out; | 
|  |  | 
|  | /* check if this file was created by spu_create */ | 
|  | ret = -EINVAL; | 
|  | if (filp->f_op != &spufs_context_fops) | 
|  | goto out; | 
|  |  | 
|  | i = SPUFS_I(file_inode(filp)); | 
|  | ret = spufs_run_spu(i->i_ctx, &npc, &status); | 
|  |  | 
|  | if (put_user(npc, unpc)) | 
|  | ret = -EFAULT; | 
|  |  | 
|  | if (ustatus && put_user(status, ustatus)) | 
|  | ret = -EFAULT; | 
|  | out: | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static long do_spu_create(const char __user *pathname, unsigned int flags, | 
|  | umode_t mode, struct file *neighbor) | 
|  | { | 
|  | struct path path; | 
|  | struct dentry *dentry; | 
|  | int ret; | 
|  |  | 
|  | dentry = user_path_create(AT_FDCWD, pathname, &path, LOOKUP_DIRECTORY); | 
|  | ret = PTR_ERR(dentry); | 
|  | if (!IS_ERR(dentry)) { | 
|  | ret = spufs_create(&path, dentry, flags, mode, neighbor); | 
|  | done_path_create(&path, dentry); | 
|  | } | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | struct spufs_calls spufs_calls = { | 
|  | .create_thread = do_spu_create, | 
|  | .spu_run = do_spu_run, | 
|  | .notify_spus_active = do_notify_spus_active, | 
|  | .owner = THIS_MODULE, | 
|  | #ifdef CONFIG_COREDUMP | 
|  | .coredump_extra_notes_size = spufs_coredump_extra_notes_size, | 
|  | .coredump_extra_notes_write = spufs_coredump_extra_notes_write, | 
|  | #endif | 
|  | }; |