static int hgcm_call_copy_back_result()

in vboxguest/vboxguest_utils.c [556:605]


static int hgcm_call_copy_back_result(
	const struct vmmdev_hgcm_call *call,
	struct vmmdev_hgcm_function_parameter *dst_parm,
	u32 parm_count, void **bounce_bufs)
{
	const struct vmmdev_hgcm_function_parameter *src_parm =
		VMMDEV_HGCM_CALL_PARMS(call);
	void __user *p;
	int ret;
	u32 i;

	/* Copy back parameters. */
	for (i = 0; i < parm_count; i++, src_parm++, dst_parm++) {
		switch (dst_parm->type) {
		case VMMDEV_HGCM_PARM_TYPE_32BIT:
		case VMMDEV_HGCM_PARM_TYPE_64BIT:
			*dst_parm = *src_parm;
			break;

		case VMMDEV_HGCM_PARM_TYPE_PAGELIST:
			dst_parm->u.page_list.size = src_parm->u.page_list.size;
			break;

		case VMMDEV_HGCM_PARM_TYPE_LINADDR_IN:
		case VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL:
		case VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL_IN:
		case VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL_OUT:
			dst_parm->u.pointer.size = src_parm->u.pointer.size;
			break;

		case VMMDEV_HGCM_PARM_TYPE_LINADDR:
		case VMMDEV_HGCM_PARM_TYPE_LINADDR_OUT:
			dst_parm->u.pointer.size = src_parm->u.pointer.size;

			p = (void __user *)dst_parm->u.pointer.u.linear_addr;
			ret = copy_to_user(p, bounce_bufs[i],
					   min(src_parm->u.pointer.size,
					       dst_parm->u.pointer.size));
			if (ret)
				return -EFAULT;
			break;

		default:
			WARN_ON(1);
			return -EINVAL;
		}
	}

	return 0;
}