aboutsummaryrefslogtreecommitdiff
path: root/vboxhgcm.h
blob: bb95eb3842f2dc9672e85b5ccf7fe4763df6eafb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/*
 * VBMouse - VirtualBox's HGCM protocol communication routines
 * Copyright (C) 2022 Javier S. Pedro
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

#ifndef VBOXHGCM_H
#define VBOXHGCM_H

#include "vbox.h"
#include "vboxdev.h"

typedef uint32_t hgcm_client_id_t;

/** Busy-waits until the request is marked as complete by VirtualBox. */
static void vbox_hgcm_wait(VMMDevHGCMRequestHeader __far * req)
{
	volatile uint32_t __far * req_flags = &req->fu32Flags;

	while (!(*req_flags & VBOX_HGCM_REQ_DONE)) {
		// TODO yield guest CPU somehow?
	}
}

static vboxerr vbox_hgcm_connect_existing(LPVBOXCOMM vb, const char *service, hgcm_client_id_t __far *client_id)
{
	VMMDevHGCMConnect __far *req = (void __far *) vb->buf;

	vbox_init_req(&req->header.header, VMMDevReq_HGCMConnect, sizeof(VMMDevHGCMConnect));
	req->loc.type = VMMDevHGCMLoc_LocalHost_Existing;
	_fstrcpy(req->loc.u.host.achName, service);

	req->u32ClientID = 7;

	vbox_send_request(vb->iobase, vb->dds.physicalAddress);

	if (req->header.header.rc < 0) {
		return req->header.header.rc;
	} else if (req->header.header.rc == VINF_HGCM_ASYNC_EXECUTE) {
		vbox_hgcm_wait(&req->header);
	}

	*client_id = req->u32ClientID;

	return req->header.result;
}

static vboxerr vbox_hgcm_disconnect(LPVBOXCOMM vb, hgcm_client_id_t client_id)
{
	VMMDevHGCMDisconnect __far *req = (void __far *) vb->buf;

	vbox_init_req(&req->header.header, VMMDevReq_HGCMDisconnect, sizeof(VMMDevHGCMDisconnect));
	req->u32ClientID = client_id;

	vbox_send_request(vb->iobase, vb->dds.physicalAddress);

	if (req->header.header.rc < 0) {
		return req->header.header.rc;
	} else if (req->header.header.rc == VINF_HGCM_ASYNC_EXECUTE) {
		vbox_hgcm_wait(&req->header);
	}

	return req->header.result;
}

static void vbox_hgcm_init_call(VMMDevHGCMCall __far *req, hgcm_client_id_t client_id, uint32_t function, unsigned narg)
{
	vbox_init_req(&req->header.header, VMMDevReq_HGCMCall32, sizeof(VMMDevHGCMCall) + (narg * sizeof(HGCMFunctionParameter)));
	req->u32ClientID = client_id;
	req->u32Function = function;
	req->cParms = narg;
}

static vboxerr vbox_hgcm_do_call_sync(LPVBOXCOMM vb, VMMDevHGCMCall __far *req)
{
	vbox_send_request(vb->iobase, vb->dds.physicalAddress);

	if (req->header.header.rc < 0) {
		return req->header.header.rc;
	} else if (req->header.header.rc == VINF_HGCM_ASYNC_EXECUTE) {
		vbox_hgcm_wait(&req->header);
	}

	return 0;
}

static void vbox_hgcm_set_parameter_uint32(VMMDevHGCMCall __far *req, unsigned arg, uint32_t value)
{
	req->aParms[arg].type = VMMDevHGCMParmType_32bit;
	req->aParms[arg].u.value32 = value;
}

static inline uint32_t vbox_hgcm_get_parameter_uint32(VMMDevHGCMCall __far *req, unsigned arg)
{
	return req->aParms[arg].u.value32;
}

static void vbox_hgcm_set_parameter_uint64(VMMDevHGCMCall __far *req, unsigned arg, uint64_t value)
{
	req->aParms[arg].type = VMMDevHGCMParmType_64bit;
	req->aParms[arg].u.value64 = value;
}

static inline uint64_t vbox_hgcm_get_parameter_uint64(VMMDevHGCMCall __far *req, unsigned arg)
{
	return req->aParms[arg].u.value64;
}

static void vbox_hgcm_set_parameter_pointer(VMMDevHGCMCall __far *req, unsigned arg, unsigned size, void __far *ptr)
{
	req->aParms[arg].type = VMMDevHGCMParmType_LinAddr;
	req->aParms[arg].u.LinAddr.cb = size;
	req->aParms[arg].u.LinAddr.uAddr = linear_addr(ptr);
}

#endif // VBOXHGCM_H