[RFC,4/6] char: fastrpc: Add support for create remote init process

Message ID 20181130104657.14875-5-srinivas.kandagatla@linaro.org
State New
Headers show
Series
  • Untitled series #16821
Related show

Commit Message

Srinivas Kandagatla Nov. 30, 2018, 10:46 a.m.
This patch adds support to create or attach remote shell process.
The shell process called fastrpc_shell_0 is usually loaded on the DSP
when a user process is spawned.

Most of the work is derived from various downstream Qualcomm kernels.
Credits to various Qualcomm authors who have contributed to this code.
Specially Tharun Kumar Merugu <mtharu@codeaurora.org>

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>

---
 drivers/char/fastrpc.c       | 172 +++++++++++++++++++++++++++++++++++
 include/uapi/linux/fastrpc.h |  18 ++++
 2 files changed, 190 insertions(+)

-- 
2.19.2

Comments

Arnd Bergmann Nov. 30, 2018, 1:26 p.m. | #1
On Fri, Nov 30, 2018 at 11:48 AM Srinivas Kandagatla
<srinivas.kandagatla@linaro.org> wrote:

> +

> +static int fastrpc_init_process(struct fastrpc_user *fl,

> +                               struct fastrpc_ioctl_init *init)

> +{

> +       struct fastrpc_ioctl_invoke *ioctl;

> +       struct fastrpc_phy_page pages[1];

> +       struct fastrpc_map *file = NULL, *mem = NULL;

> +       struct fastrpc_buf *imem = NULL;

> +       int err = 0;

> +

> +       ioctl = kzalloc(sizeof(*ioctl), GFP_KERNEL);

> +       if (!ioctl)

> +               return -ENOMEM;

> +

> +       if (init->flags == FASTRPC_INIT_ATTACH) {

> +               remote_arg_t ra[1];

> +               int tgid = fl->tgid;

> +

> +               ra[0].buf.pv = (void *)&tgid;

> +               ra[0].buf.len = sizeof(tgid);

> +               ioctl->handle = 1;

> +               ioctl->sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_ATTACH, 1, 0);

> +               ioctl->pra = ra;

> +               fl->pd = 0;

> +

> +               err = fastrpc_internal_invoke(fl, 1, ioctl);

> +               if (err)

> +                       goto bail;


It doesn't seem right to me to dynamically allocate an 'ioctl' data structure
from kernel context and pass that down to another function. Maybe eliminate
that structure and change fastrpc_internal_invoke to take the individual
arguments here instead of a pointer?

> +       } else if (init->flags == FASTRPC_INIT_CREATE) {


How about splitting each flags== case into a separate function?

> diff --git a/include/uapi/linux/fastrpc.h b/include/uapi/linux/fastrpc.h

> index 8fec66601337..6b596fc7ddf3 100644

> --- a/include/uapi/linux/fastrpc.h

> +++ b/include/uapi/linux/fastrpc.h

> @@ -6,6 +6,12 @@

>  #include <linux/types.h>

>

>  #define FASTRPC_IOCTL_INVOKE   _IOWR('R', 3, struct fastrpc_ioctl_invoke)

> +#define FASTRPC_IOCTL_INIT     _IOWR('R', 4, struct fastrpc_ioctl_init)

> +

> +/* INIT a new process or attach to guestos */

> +#define FASTRPC_INIT_ATTACH      0

> +#define FASTRPC_INIT_CREATE      1

> +#define FASTRPC_INIT_CREATE_STATIC  2


Maybe use three command codes here, and remove the 'flags' member?

> @@ -53,4 +59,16 @@ struct fastrpc_ioctl_invoke {

>         unsigned int *crc;

>  };

>

> +struct fastrpc_ioctl_init {

> +       uint32_t flags;         /* one of FASTRPC_INIT_* macros */

> +       uintptr_t file;         /* pointer to elf file */

> +       uint32_t filelen;       /* elf file length */

> +       int32_t filefd;         /* ION fd for the file */


What does this have to do with ION? The driver seems to otherwise
just use the generic dma_buf interfaces.

> +       uintptr_t mem;          /* mem for the PD */

> +       uint32_t memlen;        /* mem length */

> +       int32_t memfd;          /* fd for the mem */

> +       int attrs;

> +       unsigned int siglen;

> +};


This structure is again not suitable for ioctls. Please used fixed-length
members and no holes in the structure.

       Arnd
Srinivas Kandagatla Nov. 30, 2018, 1:34 p.m. | #2
Thanks Arnd for the review comments,

On 30/11/18 13:26, Arnd Bergmann wrote:
> On Fri, Nov 30, 2018 at 11:48 AM Srinivas Kandagatla

> <srinivas.kandagatla@linaro.org> wrote:

> 

>> +

>> +static int fastrpc_init_process(struct fastrpc_user *fl,

>> +                               struct fastrpc_ioctl_init *init)

>> +{

>> +       struct fastrpc_ioctl_invoke *ioctl;

>> +       struct fastrpc_phy_page pages[1];

>> +       struct fastrpc_map *file = NULL, *mem = NULL;

>> +       struct fastrpc_buf *imem = NULL;

>> +       int err = 0;

>> +

>> +       ioctl = kzalloc(sizeof(*ioctl), GFP_KERNEL);

>> +       if (!ioctl)

>> +               return -ENOMEM;

>> +

>> +       if (init->flags == FASTRPC_INIT_ATTACH) {

>> +               remote_arg_t ra[1];

>> +               int tgid = fl->tgid;

>> +

>> +               ra[0].buf.pv = (void *)&tgid;

>> +               ra[0].buf.len = sizeof(tgid);

>> +               ioctl->handle = 1;

>> +               ioctl->sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_ATTACH, 1, 0);

>> +               ioctl->pra = ra;

>> +               fl->pd = 0;

>> +

>> +               err = fastrpc_internal_invoke(fl, 1, ioctl);

>> +               if (err)

>> +                       goto bail;

> 

> It doesn't seem right to me to dynamically allocate an 'ioctl' data structure

> from kernel context and pass that down to another function. Maybe eliminate

> that structure and change fastrpc_internal_invoke to take the individual

> arguments here instead of a pointer?

Yes, I totally agree with you, Will rework this part as suggested.
> 

>> +       } else if (init->flags == FASTRPC_INIT_CREATE) {

> 

> How about splitting each flags== case into a separate function?


Once I move this to a command code then make this a separate function.
> 

>> diff --git a/include/uapi/linux/fastrpc.h b/include/uapi/linux/fastrpc.h

>> index 8fec66601337..6b596fc7ddf3 100644

>> --- a/include/uapi/linux/fastrpc.h

>> +++ b/include/uapi/linux/fastrpc.h

>> @@ -6,6 +6,12 @@

>>   #include <linux/types.h>

>>

>>   #define FASTRPC_IOCTL_INVOKE   _IOWR('R', 3, struct fastrpc_ioctl_invoke)

>> +#define FASTRPC_IOCTL_INIT     _IOWR('R', 4, struct fastrpc_ioctl_init)

>> +

>> +/* INIT a new process or attach to guestos */

>> +#define FASTRPC_INIT_ATTACH      0

>> +#define FASTRPC_INIT_CREATE      1

>> +#define FASTRPC_INIT_CREATE_STATIC  2

> 

> Maybe use three command codes here, and remove the 'flags' member?

> 

Make sense, will do it in next version.

>> @@ -53,4 +59,16 @@ struct fastrpc_ioctl_invoke {

>>          unsigned int *crc;

>>   };

>>

>> +struct fastrpc_ioctl_init {

>> +       uint32_t flags;         /* one of FASTRPC_INIT_* macros */

>> +       uintptr_t file;         /* pointer to elf file */

>> +       uint32_t filelen;       /* elf file length */

>> +       int32_t filefd;         /* ION fd for the file */

> 

> What does this have to do with ION? The driver seems to otherwise

> just use the generic dma_buf interfaces.

Yes, the driver just uses dma_buf, it looks like leftover from downstream!

> 

>> +       uintptr_t mem;          /* mem for the PD */

>> +       uint32_t memlen;        /* mem length */

>> +       int32_t memfd;          /* fd for the mem */

>> +       int attrs;

>> +       unsigned int siglen;

>> +};

> 

> This structure is again not suitable for ioctls. Please used fixed-length

> members and no holes in the structure.

Sure, Will recheck all the structures before sending next version!


--srini
> 

>         Arnd

>

Patch

diff --git a/drivers/char/fastrpc.c b/drivers/char/fastrpc.c
index 5bb224adc24f..3630e883d3f4 100644
--- a/drivers/char/fastrpc.c
+++ b/drivers/char/fastrpc.c
@@ -30,6 +30,8 @@ 
 #define FASTRPC_PHYS(p)	(p & 0xffffffff)
 #define FASTRPC_CTX_MAX (256)
 #define FASTRPC_CTXID_MASK (0xFF0)
+#define INIT_FILELEN_MAX (2*1024*1024)
+#define INIT_MEMLEN_MAX  (8*1024*1024)
 #define FASTRPC_DEVICE_NAME	"fastrpc"
 
 /* Retrives number of input buffers from the scalars parameter */
@@ -59,6 +61,14 @@ 
 
 #define FASTRPC_SCALARS(method, in, out) \
 		FASTRPC_BUILD_SCALARS(0, method, in, out, 0, 0)
+
+/* Remote Method id table */
+#define FASTRPC_RMID_INIT_ATTACH	0
+#define FASTRPC_RMID_INIT_RELEASE	1
+#define FASTRPC_RMID_INIT_CREATE	6
+#define FASTRPC_RMID_INIT_CREATE_ATTR	7
+#define FASTRPC_RMID_INIT_CREATE_STATIC	8
+
 #define cdev_to_cctx(d) container_of(d, struct fastrpc_channel_ctx, cdev)
 
 static const char *domains[FASTRPC_DEV_MAX] = { "adsp", "mdsp",
@@ -735,6 +745,130 @@  static int fastrpc_internal_invoke(struct fastrpc_user *fl,
 
 	return err;
 }
+
+static int fastrpc_init_process(struct fastrpc_user *fl,
+				struct fastrpc_ioctl_init *init)
+{
+	struct fastrpc_ioctl_invoke *ioctl;
+	struct fastrpc_phy_page pages[1];
+	struct fastrpc_map *file = NULL, *mem = NULL;
+	struct fastrpc_buf *imem = NULL;
+	int err = 0;
+
+	ioctl = kzalloc(sizeof(*ioctl), GFP_KERNEL);
+	if (!ioctl)
+		return -ENOMEM;
+
+	if (init->flags == FASTRPC_INIT_ATTACH) {
+		remote_arg_t ra[1];
+		int tgid = fl->tgid;
+
+		ra[0].buf.pv = (void *)&tgid;
+		ra[0].buf.len = sizeof(tgid);
+		ioctl->handle = 1;
+		ioctl->sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_ATTACH, 1, 0);
+		ioctl->pra = ra;
+		fl->pd = 0;
+
+		err = fastrpc_internal_invoke(fl, 1, ioctl);
+		if (err)
+			goto bail;
+	} else if (init->flags == FASTRPC_INIT_CREATE) {
+		int memlen;
+		remote_arg_t ra[6];
+		int fds[6];
+		struct {
+			int pgid;
+			unsigned int namelen;
+			unsigned int filelen;
+			unsigned int pageslen;
+			int attrs;
+			int siglen;
+		} inbuf;
+
+		inbuf.pgid = fl->tgid;
+		inbuf.namelen = strlen(current->comm) + 1;
+		inbuf.filelen = init->filelen;
+		fl->pd = 1;
+
+		if (init->filelen) {
+			err = fastrpc_map_create(fl, init->filefd,
+						  init->file, init->filelen,
+						  &file);
+			if (err)
+				goto bail;
+		}
+		inbuf.pageslen = 1;
+
+		if (init->mem) {
+			err = -EINVAL;
+			pr_err("adsprpc: %s: %s: ERROR: donated memory allocated in userspace\n",
+				current->comm, __func__);
+			goto bail;
+		}
+		memlen = ALIGN(max(INIT_FILELEN_MAX, (int)init->filelen * 4),
+			       1024 * 1024);
+		err = fastrpc_buf_alloc(fl, fl->sctx->dev, memlen,
+					 &imem);
+		if (err)
+			goto bail;
+
+		fl->init_mem = imem;
+		inbuf.pageslen = 1;
+		ra[0].buf.pv = (void *)&inbuf;
+		ra[0].buf.len = sizeof(inbuf);
+		fds[0] = 0;
+
+		ra[1].buf.pv = (void *)current->comm;
+		ra[1].buf.len = inbuf.namelen;
+		fds[1] = 0;
+
+		ra[2].buf.pv = (void *)init->file;
+		ra[2].buf.len = inbuf.filelen;
+		fds[2] = init->filefd;
+
+		pages[0].addr = imem->phys;
+		pages[0].size = imem->size;
+
+		ra[3].buf.pv = (void *)pages;
+		ra[3].buf.len = 1 * sizeof(*pages);
+		fds[3] = 0;
+
+		inbuf.attrs = init->attrs;
+		ra[4].buf.pv = (void *)&(inbuf.attrs);
+		ra[4].buf.len = sizeof(inbuf.attrs);
+		fds[4] = 0;
+
+		inbuf.siglen = init->siglen;
+		ra[5].buf.pv = (void *)&(inbuf.siglen);
+		ra[5].buf.len = sizeof(inbuf.siglen);
+		fds[5] = 0;
+
+		ioctl->handle = 1;
+		ioctl->sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_CREATE, 4, 0);
+		if (init->attrs)
+			ioctl->sc = FASTRPC_SCALARS(
+					FASTRPC_RMID_INIT_CREATE_ATTR, 6, 0);
+		ioctl->pra = ra;
+		ioctl->fds = fds;
+		err = fastrpc_internal_invoke(fl, 1, ioctl);
+		if (err)
+			goto bail;
+	} else {
+		err = -ENOTTY;
+	}
+bail:
+	kfree(ioctl);
+
+	if (mem && err)
+		fastrpc_map_put(mem);
+
+	if (file)
+		fastrpc_map_put(file);
+
+	return err;
+}
+
 static struct fastrpc_session_ctx *fastrpc_session_alloc(
 					struct fastrpc_channel_ctx *cctx,
 					int secure)
@@ -769,6 +903,25 @@  static const struct of_device_id fastrpc_match_table[] = {
 	{}
 };
 
+static int fastrpc_release_current_dsp_process(struct fastrpc_user *fl)
+{
+	struct fastrpc_ioctl_invoke ioctl;
+	remote_arg_t ra[1];
+	int tgid = 0;
+
+	tgid = fl->tgid;
+	ra[0].buf.pv = (void *)&tgid;
+	ra[0].buf.len = sizeof(tgid);
+	ioctl.handle = 1;
+	ioctl.sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_RELEASE, 1, 0);
+	ioctl.pra = ra;
+	ioctl.fds = NULL;
+	ioctl.attrs = NULL;
+	ioctl.crc = NULL;
+
+	return fastrpc_internal_invoke(fl, 1, &ioctl);
+}
+
 static int fastrpc_device_release(struct inode *inode, struct file *file)
 {
 	struct fastrpc_user *fl = (struct fastrpc_user *)file->private_data;
@@ -776,6 +929,8 @@  static int fastrpc_device_release(struct inode *inode, struct file *file)
 	struct fastrpc_invoke_ctx *ctx, *n;
 	struct fastrpc_map *map, *m;
 
+	fastrpc_release_current_dsp_process(fl);
+
 	spin_lock(&cctx->lock);
 	list_del(&fl->user);
 	spin_unlock(&cctx->lock);
@@ -855,6 +1010,23 @@  static long fastrpc_device_ioctl(struct file *file, unsigned int cmd,
 			goto bail;
 		break;
 		}
+	case FASTRPC_IOCTL_INIT: {
+		struct fastrpc_ioctl_init init;
+
+		init.attrs = 0;
+		init.siglen = 0;
+		err = copy_from_user(&init, argp, sizeof(init));
+		if (err)
+			goto bail;
+		if (init.filelen > INIT_FILELEN_MAX)
+			goto bail;
+		if (init.memlen > INIT_MEMLEN_MAX)
+			goto bail;
+		err = fastrpc_init_process(fl, &init);
+		if (err)
+			goto bail;
+		}
+		break;
 default:
 		err = -ENOTTY;
 		pr_info("bad ioctl: %d\n", cmd);
diff --git a/include/uapi/linux/fastrpc.h b/include/uapi/linux/fastrpc.h
index 8fec66601337..6b596fc7ddf3 100644
--- a/include/uapi/linux/fastrpc.h
+++ b/include/uapi/linux/fastrpc.h
@@ -6,6 +6,12 @@ 
 #include <linux/types.h>
 
 #define FASTRPC_IOCTL_INVOKE	_IOWR('R', 3, struct fastrpc_ioctl_invoke)
+#define FASTRPC_IOCTL_INIT	_IOWR('R', 4, struct fastrpc_ioctl_init)
+
+/* INIT a new process or attach to guestos */
+#define FASTRPC_INIT_ATTACH      0
+#define FASTRPC_INIT_CREATE      1
+#define FASTRPC_INIT_CREATE_STATIC  2
 
 #define remote_arg64_t    union remote_arg64
 
@@ -53,4 +59,16 @@  struct fastrpc_ioctl_invoke {
 	unsigned int *crc;
 };
 
+struct fastrpc_ioctl_init {
+	uint32_t flags;		/* one of FASTRPC_INIT_* macros */
+	uintptr_t file;		/* pointer to elf file */
+	uint32_t filelen;	/* elf file length */
+	int32_t filefd;		/* ION fd for the file */
+	uintptr_t mem;		/* mem for the PD */
+	uint32_t memlen;	/* mem length */
+	int32_t memfd;		/* fd for the mem */
+	int attrs;
+	unsigned int siglen;
+};
+
 #endif /* __QCOM_FASTRPC_H__ */