aboutsummaryrefslogtreecommitdiff
path: root/vboxhgcm.h
blob: 72a7481ddefb780bc3ba36e917c8187a0177aa32 (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
130
/*
 * 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?
		pause();
	}
}

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