18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci#include <linux/file.h>
38c2ecf20Sopenharmony_ci#include <linux/fs.h>
48c2ecf20Sopenharmony_ci#include <linux/export.h>
58c2ecf20Sopenharmony_ci#include <linux/mount.h>
68c2ecf20Sopenharmony_ci#include <linux/namei.h>
78c2ecf20Sopenharmony_ci#include <linux/slab.h>
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include "spufs.h"
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci/**
148c2ecf20Sopenharmony_ci * sys_spu_run - run code loaded into an SPU
158c2ecf20Sopenharmony_ci *
168c2ecf20Sopenharmony_ci * @unpc:    next program counter for the SPU
178c2ecf20Sopenharmony_ci * @ustatus: status of the SPU
188c2ecf20Sopenharmony_ci *
198c2ecf20Sopenharmony_ci * This system call transfers the control of execution of a
208c2ecf20Sopenharmony_ci * user space thread to an SPU. It will return when the
218c2ecf20Sopenharmony_ci * SPU has finished executing or when it hits an error
228c2ecf20Sopenharmony_ci * condition and it will be interrupted if a signal needs
238c2ecf20Sopenharmony_ci * to be delivered to a handler in user space.
248c2ecf20Sopenharmony_ci *
258c2ecf20Sopenharmony_ci * The next program counter is set to the passed value
268c2ecf20Sopenharmony_ci * before the SPU starts fetching code and the user space
278c2ecf20Sopenharmony_ci * pointer gets updated with the new value when returning
288c2ecf20Sopenharmony_ci * from kernel space.
298c2ecf20Sopenharmony_ci *
308c2ecf20Sopenharmony_ci * The status value returned from spu_run reflects the
318c2ecf20Sopenharmony_ci * value of the spu_status register after the SPU has stopped.
328c2ecf20Sopenharmony_ci *
338c2ecf20Sopenharmony_ci */
348c2ecf20Sopenharmony_cistatic long do_spu_run(struct file *filp,
358c2ecf20Sopenharmony_ci			__u32 __user *unpc,
368c2ecf20Sopenharmony_ci			__u32 __user *ustatus)
378c2ecf20Sopenharmony_ci{
388c2ecf20Sopenharmony_ci	long ret;
398c2ecf20Sopenharmony_ci	struct spufs_inode_info *i;
408c2ecf20Sopenharmony_ci	u32 npc, status;
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	ret = -EFAULT;
438c2ecf20Sopenharmony_ci	if (get_user(npc, unpc))
448c2ecf20Sopenharmony_ci		goto out;
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci	/* check if this file was created by spu_create */
478c2ecf20Sopenharmony_ci	ret = -EINVAL;
488c2ecf20Sopenharmony_ci	if (filp->f_op != &spufs_context_fops)
498c2ecf20Sopenharmony_ci		goto out;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	i = SPUFS_I(file_inode(filp));
528c2ecf20Sopenharmony_ci	ret = spufs_run_spu(i->i_ctx, &npc, &status);
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	if (put_user(npc, unpc))
558c2ecf20Sopenharmony_ci		ret = -EFAULT;
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	if (ustatus && put_user(status, ustatus))
588c2ecf20Sopenharmony_ci		ret = -EFAULT;
598c2ecf20Sopenharmony_ciout:
608c2ecf20Sopenharmony_ci	return ret;
618c2ecf20Sopenharmony_ci}
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_cistatic long do_spu_create(const char __user *pathname, unsigned int flags,
648c2ecf20Sopenharmony_ci		umode_t mode, struct file *neighbor)
658c2ecf20Sopenharmony_ci{
668c2ecf20Sopenharmony_ci	struct path path;
678c2ecf20Sopenharmony_ci	struct dentry *dentry;
688c2ecf20Sopenharmony_ci	int ret;
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	dentry = user_path_create(AT_FDCWD, pathname, &path, LOOKUP_DIRECTORY);
718c2ecf20Sopenharmony_ci	ret = PTR_ERR(dentry);
728c2ecf20Sopenharmony_ci	if (!IS_ERR(dentry)) {
738c2ecf20Sopenharmony_ci		ret = spufs_create(&path, dentry, flags, mode, neighbor);
748c2ecf20Sopenharmony_ci		done_path_create(&path, dentry);
758c2ecf20Sopenharmony_ci	}
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	return ret;
788c2ecf20Sopenharmony_ci}
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_cistruct spufs_calls spufs_calls = {
818c2ecf20Sopenharmony_ci	.create_thread = do_spu_create,
828c2ecf20Sopenharmony_ci	.spu_run = do_spu_run,
838c2ecf20Sopenharmony_ci	.notify_spus_active = do_notify_spus_active,
848c2ecf20Sopenharmony_ci	.owner = THIS_MODULE,
858c2ecf20Sopenharmony_ci#ifdef CONFIG_COREDUMP
868c2ecf20Sopenharmony_ci	.coredump_extra_notes_size = spufs_coredump_extra_notes_size,
878c2ecf20Sopenharmony_ci	.coredump_extra_notes_write = spufs_coredump_extra_notes_write,
888c2ecf20Sopenharmony_ci#endif
898c2ecf20Sopenharmony_ci};
90