[RESEND PATCH V4] staging: vchiq_arm: Add compatibility wrappers for ioctls

Dan Carpenter dan.carpenter at oracle.com
Mon Mar 6 07:22:39 PST 2017


On Wed, Mar 01, 2017 at 07:41:46PM -0800, Michael Zoran wrote:
> This patch adds compatibility wrappers for the ioctls
> exposed by vchiq/vc04_services.  The compat ioctls are
> completely implemented on top of the native ioctls.  No
> existing lines are modified.
> 
> While the ideal approach would be to cleanup the existing
> code, this path is simplier and easier to review. While
> it does have a small runtime performance penality vs
> seperating the existing code into wrapper+worker functions,
> the penality is small since only the metadata is copied
> back onto the 32 bit user mode stack.
> 
> The on top of approach is the approach used by several
> existing performance critical subsystems of Linux such
> as the DRM 3D graphics subsystem.
> 
> Testing:
> 
> 1. A 32 bit chroot was created on a RPI 3 and vchiq_test
> was built for armhf.  The usual tests were run such as
> vchiq_test -f 10 and vchiq_test -p.
> 
> 2. This patch was applied to the shipping version of
> the Linux kernel used for the RPI and that kernel was
> built for arm64. That kernel was used to boot Raspbian.
> Many of the builtin features are now functional such
> as the "hello_pi" examples, and minecraft_pi.
> 
> Changes:
> 	V1 - Complete rewrite of the ioctl code.
> 	V2 - Rewrite of only ioctls that change
>              between 32 bit and 64 bit.
>         V3 - Minor changes.
> 	V4(This Version) - Abandon cleaning up the
> 	     exising code and completely write the
> 	     wrappers on top of the native ioctls.
> 	     No existing lines are changed.
> 
> Signed-off-by: Michael Zoran <mzoran at crowfest.net>
> ---
>  .../vc04_services/interface/vchiq_arm/vchiq_arm.c  | 446 +++++++++++++++++++++
>  1 file changed, 446 insertions(+)
> 
> diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
> index 19bd4ac6e855..90dfa79089d3 100644
> --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
> +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
> @@ -47,6 +47,7 @@
>  #include <linux/list.h>
>  #include <linux/of.h>
>  #include <linux/platform_device.h>
> +#include <linux/compat.h>
>  #include <soc/bcm2835/raspberrypi-firmware.h>
>  
>  #include "vchiq_core.h"
> @@ -1227,6 +1228,448 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
>  	return ret;
>  }
>  
> +#if defined(CONFIG_COMPAT)
> +
> +struct vchiq_service_params32 {
> +	int fourcc;
> +	compat_uptr_t callback;
> +	compat_uptr_t userdata;
> +	short version; /* Increment for non-trivial changes */
> +	short version_min; /* Update for incompatible changes */
> +};
> +
> +struct vchiq_create_service32 {
> +	struct vchiq_service_params32 params;
> +	int is_open;
> +	int is_vchi;
> +	unsigned int handle; /* OUT */
> +};
> +
> +#define VCHIQ_IOC_CREATE_SERVICE32 \
> +	_IOWR(VCHIQ_IOC_MAGIC, 2, struct vchiq_create_service32)
> +
> +static long
> +vchiq_compat_ioctl_create_service(
> +	struct file *file,
> +	unsigned int cmd,
> +	unsigned long arg)
> +{
> +	VCHIQ_CREATE_SERVICE_T __user *args;
> +	struct vchiq_create_service32 __user *ptrargs32 =
> +		(struct vchiq_create_service32 __user *)arg;
> +	struct vchiq_create_service32 args32;
> +	long ret;
> +
> +	args = compat_alloc_user_space(sizeof(*args));
> +	if (!args)
> +		return -EFAULT;
> +
> +	if (copy_from_user(&args32,
> +			   (struct vchiq_create_service32 __user *)arg,
> +			   sizeof(args32)))
> +		return -EFAULT;
> +
> +	if (put_user(args32.params.fourcc, &args->params.fourcc) ||
> +	    put_user(compat_ptr(args32.params.callback),
> +		     &args->params.callback) ||
> +	    put_user(compat_ptr(args32.params.userdata),
> +		     &args->params.userdata) ||
> +	    put_user(args32.params.version, &args->params.version) ||
> +	    put_user(args32.params.version_min,
> +		     &args->params.version_min) ||
> +	    put_user(args32.is_open, &args->is_open) ||
> +	    put_user(args32.is_vchi, &args->is_vchi) ||
> +	    put_user(args32.handle, &args->handle))
> +		return -EFAULT;
> +
> +	ret = vchiq_ioctl(file, VCHIQ_IOC_CREATE_SERVICE, (unsigned long)args);
> +
> +	if (ret < 0)
> +		return ret;
> +
> +	if (get_user(args32.handle, &args->handle))
> +		return -EFAULT;
> +
> +	if (copy_to_user(&ptrargs32->handle,
> +			 &args32.handle,
> +			 sizeof(args32.handle)))
> +		return -EFAULT;
> +
> +	return ret;

return 0;

> +}
> +
> +struct vchiq_element32 {
> +	compat_uptr_t data;
> +	unsigned int size;
> +};
> +
> +struct vchiq_queue_message32 {
> +	unsigned int handle;
> +	unsigned int count;
> +	compat_uptr_t elements;
> +};
> +
> +#define VCHIQ_IOC_QUEUE_MESSAGE32 \
> +	_IOW(VCHIQ_IOC_MAGIC,  4, struct vchiq_queue_message32)
> +
> +static long
> +vchiq_compat_ioctl_queue_message(struct file *file,
> +				 unsigned int cmd,
> +				 unsigned long arg)
> +{
> +	VCHIQ_QUEUE_MESSAGE_T *args;
> +	VCHIQ_ELEMENT_T *elements;
> +	struct vchiq_queue_message32 args32;
> +	unsigned int count;
> +
> +	if (copy_from_user(&args32,
> +			   (struct vchiq_queue_message32 __user *)arg,
> +			   sizeof(args32)))
> +		return -EFAULT;
> +
> +	args = compat_alloc_user_space(sizeof(*args) +
> +				       (sizeof(*elements) * MAX_ELEMENTS));
> +
> +	if (!args)
> +		return -EFAULT;
> +
> +	if (put_user(args32.handle, &args->handle) ||
> +	    put_user(args32.count, &args->count) ||
> +	    put_user(compat_ptr(args32.elements), &args->elements))
> +		return -EFAULT;
> +
> +	if (args32.elements && args32.count && !(args32.count > MAX_ELEMENTS)) {
> +		struct vchiq_element32 tempelement32[MAX_ELEMENTS];
> +
> +		elements = (VCHIQ_ELEMENT_T __user *)(args + 1);
> +
> +		if (copy_from_user(&tempelement32,
> +				   compat_ptr(args32.elements),
> +				   sizeof(tempelement32)))
> +			return -EFAULT;
> +
> +		for (count = 0; count < args32.count; count++) {
> +			if (put_user(compat_ptr(tempelement32[count].data),
> +				     &elements[count].data) ||
> +			    put_user(tempelement32[count].size,
> +				     &elements[count].size))
> +				return -EFAULT;
> +		}
> +
> +		if (put_user(elements, &args->elements))
> +			return -EFAULT;
> +	}
> +
> +	return vchiq_ioctl(file, VCHIQ_IOC_QUEUE_MESSAGE, (unsigned long)args);
> +}
> +
> +struct vchiq_queue_bulk_transfer32 {
> +	unsigned int handle;
> +	compat_uptr_t data;
> +	unsigned int size;
> +	compat_uptr_t userdata;
> +	VCHIQ_BULK_MODE_T mode;
> +};
> +
> +#define VCHIQ_IOC_QUEUE_BULK_TRANSMIT32 \
> +	_IOWR(VCHIQ_IOC_MAGIC, 5, struct vchiq_queue_bulk_transfer32)
> +#define VCHIQ_IOC_QUEUE_BULK_RECEIVE32 \
> +	_IOWR(VCHIQ_IOC_MAGIC, 6, struct vchiq_queue_bulk_transfer32)
> +
> +static long
> +vchiq_compat_ioctl_queue_bulk(struct file *file,
> +			      unsigned int cmd,
> +			      unsigned long arg)
> +{
> +	VCHIQ_QUEUE_BULK_TRANSFER_T *args;
> +	struct vchiq_queue_bulk_transfer32 args32;
> +	struct vchiq_queue_bulk_transfer32 *ptrargs32 =
> +		(struct vchiq_queue_bulk_transfer32 *)arg;
> +	long ret;
> +
> +	args = compat_alloc_user_space(sizeof(*args));
> +	if (!args)
> +		return -EFAULT;
> +
> +	if (copy_from_user(&args32,
> +			   (struct vchiq_queue_bulk_transfer32 __user *)arg,
> +			   sizeof(args32)))
> +		return -EFAULT;
> +
> +	if (put_user(args32.handle, &args->handle) ||
> +	    put_user(compat_ptr(args32.data), &args->data) ||
> +	    put_user(args32.size, &args->size) ||
> +	    put_user(compat_ptr(args32.userdata), &args->userdata) ||
> +	    put_user(args32.mode, &args->mode))
> +		return -EFAULT;
> +
> +	if (cmd == VCHIQ_IOC_QUEUE_BULK_TRANSMIT32)
> +		cmd = VCHIQ_IOC_QUEUE_BULK_TRANSMIT;
> +	else
> +		cmd = VCHIQ_IOC_QUEUE_BULK_RECEIVE;
> +
> +	ret = vchiq_ioctl(file, cmd, (unsigned long)args);
> +
> +	if (ret < 0)
> +		return ret;
> +
> +	if (get_user(args32.mode, &args->mode))
> +		return -EFAULT;
> +
> +	if (copy_to_user(&ptrargs32->mode,
> +			 &args32.mode,
> +			 sizeof(args32.mode)))
> +		return -EFAULT;
> +
> +	return ret;

	return 0;

> +}
> +
> +struct vchiq_completion_data32 {
> +	VCHIQ_REASON_T reason;
> +	compat_uptr_t header;
> +	compat_uptr_t service_userdata;
> +	compat_uptr_t bulk_userdata;
> +};
> +
> +struct vchiq_await_completion32 {
> +	unsigned int count;
> +	compat_uptr_t buf;
> +	unsigned int msgbufsize;
> +	unsigned int msgbufcount; /* IN/OUT */
> +	compat_uptr_t msgbufs;
> +};
> +
> +#define VCHIQ_IOC_AWAIT_COMPLETION32 \
> +	_IOWR(VCHIQ_IOC_MAGIC, 7, struct vchiq_await_completion32)
> +
> +static long
> +vchiq_compat_ioctl_await_completion(struct file *file,
> +				    unsigned int cmd,
> +				    unsigned long arg)
> +{
> +	VCHIQ_AWAIT_COMPLETION_T *args;
> +	VCHIQ_COMPLETION_DATA_T *completion;
> +	VCHIQ_COMPLETION_DATA_T completiontemp;
> +	struct vchiq_await_completion32 args32;
> +	struct vchiq_completion_data32 completion32;
> +	unsigned int *msgbufcount32;
> +	compat_uptr_t msgbuf32;
> +	void *msgbuf;
> +	void **msgbufptr;
> +	long ret;
> +
> +	args = compat_alloc_user_space(sizeof(*args) +
> +				       sizeof(*completion) +
> +				       sizeof(*msgbufptr));
> +	if (!args)
> +		return -EFAULT;
> +
> +	completion = (VCHIQ_COMPLETION_DATA_T *)(args + 1);
> +	msgbufptr = (void __user **)(completion + 1);
> +
> +	if (copy_from_user(&args32,
> +			   (struct vchiq_completion_data32 *)arg,
> +			   sizeof(args32)))
> +		return -EFAULT;
> +
> +	if (put_user(args32.count, &args->count) ||
> +	    put_user(compat_ptr(args32.buf), &args->buf) ||
> +	    put_user(args32.msgbufsize, &args->msgbufsize) ||
> +	    put_user(args32.msgbufcount, &args->msgbufcount) ||
> +	    put_user(compat_ptr(args32.msgbufs), &args->msgbufs))
> +		return -EFAULT;
> +
> +	if (!args32.count || !args32.buf || !args32.msgbufcount)
> +		return vchiq_ioctl(file,
> +				   VCHIQ_IOC_AWAIT_COMPLETION,
> +				   (unsigned long)args);
> +
> +	if (copy_from_user(&msgbuf32,
> +			   compat_ptr(args32.msgbufs) +
> +			   (sizeof(compat_uptr_t) *
> +			   (args32.msgbufcount - 1)),
> +			   sizeof(msgbuf32)))
> +		return -EFAULT;
> +
> +	msgbuf = compat_ptr(msgbuf32);
> +
> +	if (copy_to_user(msgbufptr,
> +			 &msgbuf,
> +			 sizeof(msgbuf)))
> +		return -EFAULT;
> +
> +	if (copy_to_user(&args->msgbufs,
> +			 &msgbufptr,
> +			 sizeof(msgbufptr)))
> +		return -EFAULT;
> +
> +	if (put_user(1U, &args->count) ||
> +	    put_user(completion, &args->buf) ||
> +	    put_user(1U, &args->msgbufcount))
> +		return -EFAULT;
> +
> +	ret = vchiq_ioctl(file,
> +			  VCHIQ_IOC_AWAIT_COMPLETION,
> +			  (unsigned long)args);
> +
> +	if (ret <= 0)

Really?

> +		return ret;
> +
> +	if (copy_from_user(&completiontemp, completion, sizeof(*completion)))
> +		return -EFAULT;
> +
> +	completion32.reason = completiontemp.reason;
> +	completion32.header = ptr_to_compat(completiontemp.header);
> +	completion32.service_userdata =
> +		ptr_to_compat(completiontemp.service_userdata);
> +	completion32.bulk_userdata =
> +		ptr_to_compat(completiontemp.bulk_userdata);
> +
> +	if (copy_to_user(compat_ptr(args32.buf),
> +			 &completion32,
> +			 sizeof(completion32)))
> +		return -EFAULT;
> +
> +	args32.msgbufcount--;
> +
> +	msgbufcount32 =
> +		&((struct vchiq_await_completion32 __user *)arg)->msgbufcount;
> +
> +	if (copy_to_user(msgbufcount32,
> +			 &args32.msgbufcount,
> +			 sizeof(args32.msgbufcount)))
> +		return -EFAULT;
> +
> +	return ret;

	return 0;


regards,
dan carpenter




More information about the linux-rpi-kernel mailing list