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@xxxxxxxxxxxx> > --- > .../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 _______________________________________________ devel mailing list devel@xxxxxxxxxxxxxxxxxxxxxx http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel