162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#include <linux/file.h>
362306a36Sopenharmony_ci#include <linux/fs.h>
462306a36Sopenharmony_ci#include <linux/export.h>
562306a36Sopenharmony_ci#include <linux/mount.h>
662306a36Sopenharmony_ci#include <linux/namei.h>
762306a36Sopenharmony_ci#include <linux/slab.h>
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/uaccess.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include "spufs.h"
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci/**
1462306a36Sopenharmony_ci * sys_spu_run - run code loaded into an SPU
1562306a36Sopenharmony_ci *
1662306a36Sopenharmony_ci * @unpc:    next program counter for the SPU
1762306a36Sopenharmony_ci * @ustatus: status of the SPU
1862306a36Sopenharmony_ci *
1962306a36Sopenharmony_ci * This system call transfers the control of execution of a
2062306a36Sopenharmony_ci * user space thread to an SPU. It will return when the
2162306a36Sopenharmony_ci * SPU has finished executing or when it hits an error
2262306a36Sopenharmony_ci * condition and it will be interrupted if a signal needs
2362306a36Sopenharmony_ci * to be delivered to a handler in user space.
2462306a36Sopenharmony_ci *
2562306a36Sopenharmony_ci * The next program counter is set to the passed value
2662306a36Sopenharmony_ci * before the SPU starts fetching code and the user space
2762306a36Sopenharmony_ci * pointer gets updated with the new value when returning
2862306a36Sopenharmony_ci * from kernel space.
2962306a36Sopenharmony_ci *
3062306a36Sopenharmony_ci * The status value returned from spu_run reflects the
3162306a36Sopenharmony_ci * value of the spu_status register after the SPU has stopped.
3262306a36Sopenharmony_ci *
3362306a36Sopenharmony_ci */
3462306a36Sopenharmony_cistatic long do_spu_run(struct file *filp,
3562306a36Sopenharmony_ci			__u32 __user *unpc,
3662306a36Sopenharmony_ci			__u32 __user *ustatus)
3762306a36Sopenharmony_ci{
3862306a36Sopenharmony_ci	long ret;
3962306a36Sopenharmony_ci	struct spufs_inode_info *i;
4062306a36Sopenharmony_ci	u32 npc, status;
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	ret = -EFAULT;
4362306a36Sopenharmony_ci	if (get_user(npc, unpc))
4462306a36Sopenharmony_ci		goto out;
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	/* check if this file was created by spu_create */
4762306a36Sopenharmony_ci	ret = -EINVAL;
4862306a36Sopenharmony_ci	if (filp->f_op != &spufs_context_fops)
4962306a36Sopenharmony_ci		goto out;
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	i = SPUFS_I(file_inode(filp));
5262306a36Sopenharmony_ci	ret = spufs_run_spu(i->i_ctx, &npc, &status);
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	if (put_user(npc, unpc))
5562306a36Sopenharmony_ci		ret = -EFAULT;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	if (ustatus && put_user(status, ustatus))
5862306a36Sopenharmony_ci		ret = -EFAULT;
5962306a36Sopenharmony_ciout:
6062306a36Sopenharmony_ci	return ret;
6162306a36Sopenharmony_ci}
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_cistatic long do_spu_create(const char __user *pathname, unsigned int flags,
6462306a36Sopenharmony_ci		umode_t mode, struct file *neighbor)
6562306a36Sopenharmony_ci{
6662306a36Sopenharmony_ci	struct path path;
6762306a36Sopenharmony_ci	struct dentry *dentry;
6862306a36Sopenharmony_ci	int ret;
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	dentry = user_path_create(AT_FDCWD, pathname, &path, LOOKUP_DIRECTORY);
7162306a36Sopenharmony_ci	ret = PTR_ERR(dentry);
7262306a36Sopenharmony_ci	if (!IS_ERR(dentry)) {
7362306a36Sopenharmony_ci		ret = spufs_create(&path, dentry, flags, mode, neighbor);
7462306a36Sopenharmony_ci		done_path_create(&path, dentry);
7562306a36Sopenharmony_ci	}
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	return ret;
7862306a36Sopenharmony_ci}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_cistruct spufs_calls spufs_calls = {
8162306a36Sopenharmony_ci	.create_thread = do_spu_create,
8262306a36Sopenharmony_ci	.spu_run = do_spu_run,
8362306a36Sopenharmony_ci	.notify_spus_active = do_notify_spus_active,
8462306a36Sopenharmony_ci	.owner = THIS_MODULE,
8562306a36Sopenharmony_ci#ifdef CONFIG_COREDUMP
8662306a36Sopenharmony_ci	.coredump_extra_notes_size = spufs_coredump_extra_notes_size,
8762306a36Sopenharmony_ci	.coredump_extra_notes_write = spufs_coredump_extra_notes_write,
8862306a36Sopenharmony_ci#endif
8962306a36Sopenharmony_ci};
90