struct user_service {
        struct vchiq_service *service;
-       void *userdata;
+       void __user *userdata;
        struct vchiq_instance *instance;
        char is_vchi;
        char dequeue_pending;
 
 struct vchiq_instance {
        struct vchiq_state *state;
-       struct vchiq_completion_data completions[MAX_COMPLETIONS];
+       struct vchiq_completion_data_kernel completions[MAX_COMPLETIONS];
        int completion_insert;
        int completion_remove;
        struct completion insert_event;
 
 static enum vchiq_status vchiq_add_service(
        struct vchiq_instance             *instance,
-       const struct vchiq_service_params *params,
+       const struct vchiq_service_params_kernel *params,
        unsigned int       *phandle)
 {
        enum vchiq_status status;
 
 enum vchiq_status vchiq_open_service(
        struct vchiq_instance             *instance,
-       const struct vchiq_service_params *params,
+       const struct vchiq_service_params_kernel *params,
        unsigned int       *phandle)
 {
        enum vchiq_status   status = VCHIQ_ERROR;
                switch (mode) {
                case VCHIQ_BULK_MODE_NOCALLBACK:
                case VCHIQ_BULK_MODE_CALLBACK:
-                       status = vchiq_bulk_transfer(handle, (void *)data, size,
+                       status = vchiq_bulk_transfer(handle,
+                                                    (void *)data, size,
                                                     userdata, mode,
                                                     VCHIQ_BULK_TRANSMIT);
                        break;
 
                if (bulk) {
                        /* This thread has an outstanding bulk transfer. */
-                       if ((bulk->data != data) ||
+                       /* FIXME: why compare a dma address to a pointer? */
+                       if ((bulk->data != (dma_addr_t)(uintptr_t)data) ||
                                (bulk->size != size)) {
                                /* This is not a retry of the previous one.
                                 * Cancel the signal when the transfer
               struct vchiq_header *header, struct user_service *user_service,
               void *bulk_userdata)
 {
-       struct vchiq_completion_data *completion;
+       struct vchiq_completion_data_kernel *completion;
        int insert;
 
        DEBUG_INITIALISE(g_state.local)
        struct user_service *user_service = NULL;
        struct vchiq_service *service;
        enum vchiq_status status = VCHIQ_SUCCESS;
-       void *userdata;
+       struct vchiq_service_params_kernel params;
        int srvstate;
 
        user_service = kmalloc(sizeof(*user_service), GFP_KERNEL);
                         VCHIQ_SRVSTATE_LISTENING : VCHIQ_SRVSTATE_HIDDEN;
        }
 
-       userdata = args->params.userdata;
-       args->params.callback = service_callback;
-       args->params.userdata = user_service;
-       service = vchiq_add_service_internal(instance->state, &args->params,
+       params = (struct vchiq_service_params_kernel) {
+               .fourcc   = args->params.fourcc,
+               .callback = service_callback,
+               .userdata = user_service,
+               .version  = args->params.version,
+               .version_min = args->params.version_min,
+       };
+       service = vchiq_add_service_internal(instance->state, ¶ms,
                                             srvstate, instance,
                                             user_service_free);
-
        if (!service) {
                kfree(user_service);
                return -EEXIST;
        }
 
        user_service->service = service;
-       user_service->userdata = userdata;
+       user_service->userdata = args->params.userdata;
        user_service->instance = instance;
        user_service->is_vchi = (args->is_vchi != 0);
        user_service->dequeue_pending = 0;
 {
        struct vchiq_service *service;
        struct bulk_waiter_node *waiter = NULL;
+       void *userdata;
        int status = 0;
        int ret;
 
                        goto out;
                }
 
-               args->userdata = &waiter->bulk_waiter;
+               userdata = &waiter->bulk_waiter;
        } else if (args->mode == VCHIQ_BULK_MODE_WAITING) {
                mutex_lock(&instance->bulk_waiter_list_mutex);
                list_for_each_entry(waiter, &instance->bulk_waiter_list,
                vchiq_log_info(vchiq_arm_log_level,
                        "found bulk_waiter %pK for pid %d", waiter,
                        current->pid);
-               args->userdata = &waiter->bulk_waiter;
+               userdata = &waiter->bulk_waiter;
        }
 
+       /*
+        * FIXME address space mismatch:
+        * args->data may be interpreted as a kernel pointer
+        * in create_pagelist() called from vchiq_bulk_transfer(),
+        * accessing kernel data instead of user space, based on the
+        * address.
+        */
        status = vchiq_bulk_transfer(args->handle, args->data, args->size,
-                                    args->userdata, args->mode, dir);
+                                    userdata, args->mode, dir);
 
        if (!waiter) {
                ret = 0;
        return 0;
 }
 
+/* read a user pointer value from an array pointers in user space */
 static inline int vchiq_get_user_ptr(void __user **buf, void __user *ubuf, int index)
 {
-       compat_uptr_t ptr32;
        int ret;
 
        if (in_compat_syscall()) {
+               compat_uptr_t ptr32;
                compat_uptr_t __user *uptr = ubuf;
-               ret = get_user(ptr32, &uptr[index]);
+               ret = get_user(ptr32, uptr + index);
                *buf = compat_ptr(ptr32);
        } else {
-               void __user *__user *uptr = ubuf;
-               ret = get_user(buf, &uptr[index]);
+               uintptr_t ptr, __user *uptr = ubuf;
+               ret = get_user(ptr, uptr + index);
+               *buf = (void __user *)ptr;
        }
+
        return ret;
 }
 
 
        if (in_compat_syscall()) {
                struct vchiq_completion_data32 tmp = {
-                       .reason           = buf->reason,
-                       .header           = ptr_to_compat(buf->header),
-                       .service_userdata = ptr_to_compat(buf->service_userdata),
-                       .bulk_userdata    = ptr_to_compat(buf->bulk_userdata),
+                       .reason           = completion->reason,
+                       .header           = ptr_to_compat(completion->header),
+                       .service_userdata = ptr_to_compat(completion->service_userdata),
+                       .bulk_userdata    = ptr_to_compat(completion->bulk_userdata),
                };
                if (copy_to_user(&buf32[index], &tmp, sizeof(tmp)))
                        return -EFAULT;
        remove = instance->completion_remove;
 
        for (ret = 0; ret < args->count; ret++) {
-               struct vchiq_completion_data *completion;
+               struct vchiq_completion_data_kernel *completion;
+               struct vchiq_completion_data user_completion;
                struct vchiq_service *service;
                struct user_service *user_service;
                struct vchiq_header *header;
 
                service = completion->service_userdata;
                user_service = service->base.userdata;
-               completion->service_userdata = user_service->userdata;
+
+               memset(&user_completion, 0, sizeof(user_completion));
+               user_completion = (struct vchiq_completion_data) {
+                       .reason = completion->reason,
+                       .service_userdata = user_service->userdata,
+               };
 
                header = completion->header;
                if (header) {
                                break;
                        /* Get the pointer from user space */
                        msgbufcount--;
-                       if (vchiq_get_user_ptr(&msgbuf, &args->msgbufs,
+                       if (vchiq_get_user_ptr(&msgbuf, args->msgbufs,
                                                msgbufcount)) {
                                if (ret == 0)
                                        ret = -EFAULT;
 
                        /* The completion must point to the
                        ** msgbuf. */
-                       completion->header =
-                               (struct vchiq_header __force *)msgbuf;
+                       user_completion.header = msgbuf;
                }
 
                if ((completion->reason == VCHIQ_SERVICE_CLOSED) &&
                    !instance->use_close_delivered)
                        unlock_service(service);
 
-               if (vchiq_put_completion(args->buf, completion, ret)) {
+               /*
+                * FIXME: address space mismatch, does bulk_userdata
+                * actually point to user or kernel memory?
+                */
+               user_completion.bulk_userdata = completion->bulk_userdata;
+
+               if (vchiq_put_completion(args->buf, &user_completion, ret)) {
                        if (ret == 0)
                                ret = -EFAULT;
                        break;
 static long
 vchiq_compat_ioctl_await_completion(struct file *file,
                                    unsigned int cmd,
-                                   struct vchiq_await_completion32 *argp)
+                                   struct vchiq_await_completion32 __user *argp)
 {
        struct vchiq_await_completion args;
        struct vchiq_await_completion32 args32;
        /* Release any closed services */
        while (instance->completion_remove !=
                instance->completion_insert) {
-               struct vchiq_completion_data *completion;
+               struct vchiq_completion_data_kernel *completion;
                struct vchiq_service *service;
 
                completion = &instance->completions[
        struct vchiq_instance *instance;
        unsigned int ka_handle;
 
-       struct vchiq_service_params params = {
+       struct vchiq_service_params_kernel params = {
                .fourcc      = VCHIQ_MAKE_FOURCC('K', 'E', 'E', 'P'),
                .callback    = vchiq_keepalive_vchiq_callback,
                .version     = KEEPALIVE_VER,
 
                                bulk->remote_size);
                } else {
                        /* fabricate a matching dummy bulk */
-                       bulk->data = NULL;
+                       bulk->data = 0;
                        bulk->size = 0;
                        bulk->actual = VCHIQ_BULK_ACTUAL_ABORTED;
                        bulk->dir = is_tx ? VCHIQ_BULK_TRANSMIT :
                                queue->remote_insert++;
 
                                vchiq_log_info(vchiq_core_log_level,
-                                       "%d: prs %s@%pK (%d->%d) %x@%pK",
+                                       "%d: prs %s@%pK (%d->%d) %x@%pad",
                                        state->id, msg_type_str(type),
                                        header, remoteport, localport,
-                                       bulk->actual, bulk->data);
+                                       bulk->actual, &bulk->data);
 
                                vchiq_log_trace(vchiq_core_log_level,
                                        "%d: prs:%d %cx li=%x ri=%x p=%x",
 }
 EXPORT_SYMBOL(vchiq_msg_hold);
 
-static int vchiq_validate_params(const struct vchiq_service_params *params)
+static int vchiq_validate_params(const struct vchiq_service_params_kernel *params)
 {
        if (!params->callback || !params->fourcc) {
                vchiq_loud_error("Can't add service, invalid params\n");
 /* Called from application thread when a client or server service is created. */
 struct vchiq_service *
 vchiq_add_service_internal(struct vchiq_state *state,
-                          const struct vchiq_service_params *params,
+                          const struct vchiq_service_params_kernel *params,
                           int srvstate, struct vchiq_instance *instance,
                           vchiq_userdata_term userdata_term)
 {
  * structure.
  */
 enum vchiq_status vchiq_bulk_transfer(unsigned int handle,
-                                  void *offset, int size, void *userdata,
+                                  void *offset, int size,
+                                  void *userdata,
                                   enum vchiq_bulk_mode mode,
                                   enum vchiq_bulk_dir dir)
 {
        wmb();
 
        vchiq_log_info(vchiq_core_log_level,
-               "%d: bt (%d->%d) %cx %x@%pK %pK",
+               "%d: bt (%d->%d) %cx %x@%pad %pK",
                state->id, service->localport, service->remoteport, dir_char,
-               size, bulk->data, userdata);
+               size, &bulk->data, userdata);
 
        /* The slot mutex must be held when the service is being closed, so
           claim it here to ensure that isn't happening */
        if (service->srvstate != VCHIQ_SRVSTATE_OPEN)
                goto unlock_both_error_exit;
 
-       payload[0] = (int)(long)bulk->data;
+       payload[0] = lower_32_bits(bulk->data);
        payload[1] = bulk->size;
        status = queue_message(state,
                               NULL,