/* Get the pointer to the first parameter of a HGCM call request. */ #define VMMDEV_HGCM_CALL_PARMS(a) \
((struct vmmdev_hgcm_function_parameter *)( \
(u8 *)(a) + sizeof(struct vmmdev_hgcm_call)))
/* The max parameter buffer size for a user request. */ #define VBG_MAX_HGCM_USER_PARM (24 * SZ_1M) /* The max parameter buffer size for a kernel request. */ #define VBG_MAX_HGCM_KERNEL_PARM (16 * SZ_1M)
#define VBG_DEBUG_PORT 0x504
/* This protects vbg_log_buf and serializes VBG_DEBUG_PORT accesses */ static DEFINE_SPINLOCK(vbg_log_lock); staticchar vbg_log_buf[128];
/* Note this function returns a VBox status code, not a negative errno!! */ int vbg_req_perform(struct vbg_dev *gdev, void *req)
{ unsignedlong phys_req = virt_to_phys(req);
for (i = 0; i < parm_count; i++, src_parm++) { switch (src_parm->type) { case VMMDEV_HGCM_PARM_TYPE_32BIT: case VMMDEV_HGCM_PARM_TYPE_64BIT: break;
case VMMDEV_HGCM_PARM_TYPE_LINADDR: case VMMDEV_HGCM_PARM_TYPE_LINADDR_IN: case VMMDEV_HGCM_PARM_TYPE_LINADDR_OUT: if (!bounce_bufs) {
bounce_bufs = kcalloc(parm_count, sizeof(void *),
GFP_KERNEL); if (!bounce_bufs) return -ENOMEM;
*bounce_bufs_ret = bounce_bufs;
}
ret = hgcm_call_preprocess_linaddr(src_parm,
&bounce_bufs[i],
extra); if (ret) return ret;
break;
case VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL: case VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL_IN: case VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL_OUT:
buf = (void *)src_parm->u.pointer.u.linear_addr;
len = src_parm->u.pointer.size; if (WARN_ON(len > VBG_MAX_HGCM_KERNEL_PARM)) return -E2BIG;
for (i = 0; i < parm_count; i++, src_parm++, dst_parm++) { switch (src_parm->type) { case VMMDEV_HGCM_PARM_TYPE_32BIT: case VMMDEV_HGCM_PARM_TYPE_64BIT:
*dst_parm = *src_parm; break;
case VMMDEV_HGCM_PARM_TYPE_LINADDR: case VMMDEV_HGCM_PARM_TYPE_LINADDR_IN: case VMMDEV_HGCM_PARM_TYPE_LINADDR_OUT:
hgcm_call_init_linaddr(call, dst_parm, bounce_bufs[i],
src_parm->u.pointer.size,
src_parm->type, &off_extra); break;
case VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL: case VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL_IN: case VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL_OUT:
buf = (void *)src_parm->u.pointer.u.linear_addr;
hgcm_call_init_linaddr(call, dst_parm, buf,
src_parm->u.pointer.size,
src_parm->type, &off_extra); break;
/* Host decided to process the request asynchronously, wait for it */ if (timeout_ms == U32_MAX)
timeout = MAX_SCHEDULE_TIMEOUT; else
timeout = msecs_to_jiffies(timeout_ms);
if (WARN_ON(timeout == 0)) { /* We really should never get here */
vbg_err("%s: Call timedout and cancellation failed, leaking the request\n",
__func__);
*leak_it = true; return ret;
}
/* The call has completed normally after all */ return0;
}
/* 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;
}
}
return0;
}
int vbg_hgcm_call(struct vbg_dev *gdev, u32 requestor, u32 client_id,
u32 function, u32 timeout_ms, struct vmmdev_hgcm_function_parameter *parms, u32 parm_count, int *vbox_status)
{ struct vmmdev_hgcm_call *call; void **bounce_bufs = NULL; bool leak_it;
size_t size; int i, ret;
size = sizeof(struct vmmdev_hgcm_call) +
parm_count * sizeof(struct vmmdev_hgcm_function_parameter); /* *Validateandbuffertheparametersforthecall.Thisalsoincreases *call_sizewiththeamountofextraspaceneededforpagelists.
*/
ret = hgcm_call_preprocess(parms, parm_count, &bounce_bufs, &size); if (ret) { /* Even on error bounce bufs may still have been allocated */ goto free_bounce_bufs;
}
call = vbg_req_alloc(size, VMMDEVREQ_HGCM_CALL, requestor); if (!call) {
ret = -ENOMEM; goto free_bounce_bufs;
}
ret = vbg_hgcm_do_call(gdev, call, timeout_ms,
requestor & VMMDEV_REQUESTOR_USERMODE, &leak_it); if (ret == 0) {
*vbox_status = call->header.result;
ret = hgcm_call_copy_back_result(call, parms, parm_count,
bounce_bufs);
}
if (!leak_it)
vbg_req_free(call, size);
free_bounce_bufs: if (bounce_bufs) { for (i = 0; i < parm_count; i++)
kvfree(bounce_bufs[i]);
kfree(bounce_bufs);
}
return ret;
}
EXPORT_SYMBOL(vbg_hgcm_call);
#ifdef CONFIG_COMPAT int vbg_hgcm_call32( struct vbg_dev *gdev, u32 requestor, u32 client_id, u32 function,
u32 timeout_ms, struct vmmdev_hgcm_function_parameter32 *parm32,
u32 parm_count, int *vbox_status)
{ struct vmmdev_hgcm_function_parameter *parm64 = NULL;
u32 i, size; int ret = 0;
/* KISS allocate a temporary request and convert the parameters. */
size = parm_count * sizeof(struct vmmdev_hgcm_function_parameter);
parm64 = kzalloc(size, GFP_KERNEL); if (!parm64) return -ENOMEM;
for (i = 0; i < parm_count; i++) { switch (parm32[i].type) { case VMMDEV_HGCM_PARM_TYPE_32BIT:
parm64[i].type = VMMDEV_HGCM_PARM_TYPE_32BIT;
parm64[i].u.value32 = parm32[i].u.value32; break;
case VMMDEV_HGCM_PARM_TYPE_64BIT:
parm64[i].type = VMMDEV_HGCM_PARM_TYPE_64BIT;
parm64[i].u.value64 = parm32[i].u.value64; break;
case VMMDEV_HGCM_PARM_TYPE_LINADDR_OUT: case VMMDEV_HGCM_PARM_TYPE_LINADDR: case VMMDEV_HGCM_PARM_TYPE_LINADDR_IN:
parm64[i].type = parm32[i].type;
parm64[i].u.pointer.size = parm32[i].u.pointer.size;
parm64[i].u.pointer.u.linear_addr =
parm32[i].u.pointer.u.linear_addr; break;
default:
ret = -EINVAL;
} if (ret < 0) goto out_free;
}
ret = vbg_hgcm_call(gdev, requestor, client_id, function, timeout_ms,
parm64, parm_count, vbox_status); if (ret < 0) goto out_free;
/* Copy back. */ for (i = 0; i < parm_count; i++, parm32++, parm64++) { switch (parm64[i].type) { case VMMDEV_HGCM_PARM_TYPE_32BIT:
parm32[i].u.value32 = parm64[i].u.value32; break;
case VMMDEV_HGCM_PARM_TYPE_64BIT:
parm32[i].u.value64 = parm64[i].u.value64; break;
case VMMDEV_HGCM_PARM_TYPE_LINADDR_OUT: case VMMDEV_HGCM_PARM_TYPE_LINADDR: case VMMDEV_HGCM_PARM_TYPE_LINADDR_IN:
parm32[i].u.pointer.size = parm64[i].u.pointer.size; break;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.