xref: /minix3/minix/drivers/vmm_guest/vbox/hgcm.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
1*433d6423SLionel Sambuc /* VirtualBox driver - by D.C. van Moolenbroek */
2*433d6423SLionel Sambuc #include <machine/vmparam.h>
3*433d6423SLionel Sambuc 
4*433d6423SLionel Sambuc #include <minix/drivers.h>
5*433d6423SLionel Sambuc #include <minix/vboxtype.h>
6*433d6423SLionel Sambuc #include <minix/vboxif.h>
7*433d6423SLionel Sambuc #include <assert.h>
8*433d6423SLionel Sambuc 
9*433d6423SLionel Sambuc #include "vmmdev.h"
10*433d6423SLionel Sambuc #include "proto.h"
11*433d6423SLionel Sambuc 
12*433d6423SLionel Sambuc #define MAX_CONNS	4	/* maximum number of HGCM connections */
13*433d6423SLionel Sambuc #define MAX_REQS	2	/* number of concurrent requests per conn. */
14*433d6423SLionel Sambuc #define MAX_PARAMS	8	/* maximum number of parameters per request */
15*433d6423SLionel Sambuc 
16*433d6423SLionel Sambuc /* HGCM connection states. */
17*433d6423SLionel Sambuc enum {
18*433d6423SLionel Sambuc   STATE_FREE,
19*433d6423SLionel Sambuc   STATE_OPENING,
20*433d6423SLionel Sambuc   STATE_OPEN,
21*433d6423SLionel Sambuc   STATE_CLOSING
22*433d6423SLionel Sambuc };
23*433d6423SLionel Sambuc 
24*433d6423SLionel Sambuc /* HGCM connection information. */
25*433d6423SLionel Sambuc static struct {
26*433d6423SLionel Sambuc   int state;					/* connection state */
27*433d6423SLionel Sambuc   endpoint_t endpt;				/* caller endpoint */
28*433d6423SLionel Sambuc   u32_t client_id;				/* VMMDev-given client ID */
29*433d6423SLionel Sambuc   struct {
30*433d6423SLionel Sambuc 	int busy;				/* is this request ongoing? */
31*433d6423SLionel Sambuc 	struct VMMDevHGCMHeader *ptr;		/* request buffer */
32*433d6423SLionel Sambuc 	phys_bytes addr;			/* buffer's physical address */
33*433d6423SLionel Sambuc 
34*433d6423SLionel Sambuc 	int status;				/* IPC status of request */
35*433d6423SLionel Sambuc 	long id;				/* request ID */
36*433d6423SLionel Sambuc 
37*433d6423SLionel Sambuc 	cp_grant_id_t grant;			/* grant for parameters */
38*433d6423SLionel Sambuc 	int count;				/* number of parameters */
39*433d6423SLionel Sambuc 	vbox_param_t param[MAX_PARAMS];		/* local copy of parameters */
40*433d6423SLionel Sambuc   } req[MAX_REQS];				/* concurrent requests */
41*433d6423SLionel Sambuc } hgcm_conn[MAX_CONNS];
42*433d6423SLionel Sambuc 
43*433d6423SLionel Sambuc /*===========================================================================*
44*433d6423SLionel Sambuc  *				convert_result				     *
45*433d6423SLionel Sambuc  *===========================================================================*/
convert_result(int res)46*433d6423SLionel Sambuc static int convert_result(int res)
47*433d6423SLionel Sambuc {
48*433d6423SLionel Sambuc 	/* Convert a VirtualBox result code to a POSIX error code.
49*433d6423SLionel Sambuc 	 */
50*433d6423SLionel Sambuc 
51*433d6423SLionel Sambuc 	/* HGCM transport error codes. */
52*433d6423SLionel Sambuc 	switch (res) {
53*433d6423SLionel Sambuc 	case VMMDEV_ERR_HGCM_NOT_FOUND:		return ESRCH;
54*433d6423SLionel Sambuc 	case VMMDEV_ERR_HGCM_DENIED:		return EPERM;
55*433d6423SLionel Sambuc 	case VMMDEV_ERR_HGCM_INVALID_ADDR:	return EFAULT;
56*433d6423SLionel Sambuc 	case VMMDEV_ERR_HGCM_ASYNC_EXEC:	return EDONTREPLY;
57*433d6423SLionel Sambuc 	case VMMDEV_ERR_HGCM_INTERNAL:		return EGENERIC;
58*433d6423SLionel Sambuc 	case VMMDEV_ERR_HGCM_INVALID_ID:	return EINVAL;
59*433d6423SLionel Sambuc 	}
60*433d6423SLionel Sambuc 
61*433d6423SLionel Sambuc 	/* Positive codes are success codes. */
62*433d6423SLionel Sambuc 	if (res >= 0)
63*433d6423SLionel Sambuc 		return OK;
64*433d6423SLionel Sambuc 
65*433d6423SLionel Sambuc 	/* Unsupported negative codes are translated to EGENERIC; it is up to
66*433d6423SLionel Sambuc 	 * the caller to check the actual VirtualBox result code in that case.
67*433d6423SLionel Sambuc 	 */
68*433d6423SLionel Sambuc 	return convert_err(res);
69*433d6423SLionel Sambuc }
70*433d6423SLionel Sambuc 
71*433d6423SLionel Sambuc /*===========================================================================*
72*433d6423SLionel Sambuc  *				send_reply				     *
73*433d6423SLionel Sambuc  *===========================================================================*/
send_reply(endpoint_t endpt,int ipc_status,int result,int code,long id)74*433d6423SLionel Sambuc static void send_reply(endpoint_t endpt, int ipc_status, int result, int code,
75*433d6423SLionel Sambuc 	long id)
76*433d6423SLionel Sambuc {
77*433d6423SLionel Sambuc 	/* Send a reply to an earlier request. */
78*433d6423SLionel Sambuc 	message m;
79*433d6423SLionel Sambuc 	int r;
80*433d6423SLionel Sambuc 
81*433d6423SLionel Sambuc 	memset(&m, 0, sizeof(m));
82*433d6423SLionel Sambuc 	m.m_type = VBOX_REPLY;
83*433d6423SLionel Sambuc 	m.VBOX_RESULT = result;
84*433d6423SLionel Sambuc 	m.VBOX_CODE = code;
85*433d6423SLionel Sambuc 	m.VBOX_ID = id;
86*433d6423SLionel Sambuc 
87*433d6423SLionel Sambuc 	if (IPC_STATUS_CALL(ipc_status) == SENDREC)
88*433d6423SLionel Sambuc 		r = ipc_sendnb(endpt, &m);
89*433d6423SLionel Sambuc 	else
90*433d6423SLionel Sambuc 		r = asynsend3(endpt, &m, AMF_NOREPLY);
91*433d6423SLionel Sambuc 
92*433d6423SLionel Sambuc 	if (r != OK)
93*433d6423SLionel Sambuc 		printf("VBOX: unable to send reply to %d: %d\n", endpt, r);
94*433d6423SLionel Sambuc }
95*433d6423SLionel Sambuc 
96*433d6423SLionel Sambuc /*===========================================================================*
97*433d6423SLionel Sambuc  *				alloc_req				     *
98*433d6423SLionel Sambuc  *===========================================================================*/
alloc_req(int conn)99*433d6423SLionel Sambuc static int alloc_req(int conn)
100*433d6423SLionel Sambuc {
101*433d6423SLionel Sambuc 	/* Allocate a request for the given connection. Allocate memory as
102*433d6423SLionel Sambuc 	 * necessary. Do not mark the request as busy, as it may end up not
103*433d6423SLionel Sambuc 	 * being used.
104*433d6423SLionel Sambuc 	 */
105*433d6423SLionel Sambuc 	phys_bytes addr;
106*433d6423SLionel Sambuc 	void *ptr;
107*433d6423SLionel Sambuc 	int req;
108*433d6423SLionel Sambuc 
109*433d6423SLionel Sambuc 	for (req = 0; req < MAX_REQS; req++)
110*433d6423SLionel Sambuc 		if (!hgcm_conn[conn].req[req].busy)
111*433d6423SLionel Sambuc 			break;
112*433d6423SLionel Sambuc 
113*433d6423SLionel Sambuc 	if (req == MAX_REQS)
114*433d6423SLionel Sambuc 		return EMFILE;
115*433d6423SLionel Sambuc 
116*433d6423SLionel Sambuc 	if (hgcm_conn[conn].req[req].ptr == NULL) {
117*433d6423SLionel Sambuc 		if ((ptr = alloc_contig(VMMDEV_BUF_SIZE, 0, &addr)) == NULL)
118*433d6423SLionel Sambuc 			return ENOMEM;
119*433d6423SLionel Sambuc 
120*433d6423SLionel Sambuc 		hgcm_conn[conn].req[req].ptr = (struct VMMDevHGCMHeader *) ptr;
121*433d6423SLionel Sambuc 		hgcm_conn[conn].req[req].addr = addr;
122*433d6423SLionel Sambuc 	}
123*433d6423SLionel Sambuc 
124*433d6423SLionel Sambuc 	return req;
125*433d6423SLionel Sambuc }
126*433d6423SLionel Sambuc 
127*433d6423SLionel Sambuc /*===========================================================================*
128*433d6423SLionel Sambuc  *				free_conn				     *
129*433d6423SLionel Sambuc  *===========================================================================*/
free_conn(int conn)130*433d6423SLionel Sambuc static void free_conn(int conn)
131*433d6423SLionel Sambuc {
132*433d6423SLionel Sambuc 	/* Free the memory for all requests of the given connections, and mark
133*433d6423SLionel Sambuc 	 * the connection as free.
134*433d6423SLionel Sambuc 	 */
135*433d6423SLionel Sambuc 	void *ptr;
136*433d6423SLionel Sambuc 	int req;
137*433d6423SLionel Sambuc 
138*433d6423SLionel Sambuc 	for (req = 0; req < MAX_REQS; req++) {
139*433d6423SLionel Sambuc 		if ((ptr = (void *) hgcm_conn[conn].req[req].ptr) != NULL) {
140*433d6423SLionel Sambuc 			assert(!hgcm_conn[conn].req[req].busy);
141*433d6423SLionel Sambuc 
142*433d6423SLionel Sambuc 			free_contig(ptr, VMMDEV_BUF_SIZE);
143*433d6423SLionel Sambuc 
144*433d6423SLionel Sambuc 			hgcm_conn[conn].req[req].ptr = NULL;
145*433d6423SLionel Sambuc 		}
146*433d6423SLionel Sambuc 	}
147*433d6423SLionel Sambuc 
148*433d6423SLionel Sambuc 	hgcm_conn[conn].state = STATE_FREE;
149*433d6423SLionel Sambuc }
150*433d6423SLionel Sambuc 
151*433d6423SLionel Sambuc /*===========================================================================*
152*433d6423SLionel Sambuc  *				start_req				     *
153*433d6423SLionel Sambuc  *===========================================================================*/
start_req(int conn,int req,int type,size_t size,int ipc_status,long id,int * code)154*433d6423SLionel Sambuc static int start_req(int conn, int req, int type, size_t size, int ipc_status,
155*433d6423SLionel Sambuc 	long id, int *code)
156*433d6423SLionel Sambuc {
157*433d6423SLionel Sambuc 	/* Start a request. */
158*433d6423SLionel Sambuc 	int r, res;
159*433d6423SLionel Sambuc 
160*433d6423SLionel Sambuc 	hgcm_conn[conn].req[req].ptr->flags = 0;
161*433d6423SLionel Sambuc 	hgcm_conn[conn].req[req].ptr->result = VMMDEV_ERR_GENERIC;
162*433d6423SLionel Sambuc 
163*433d6423SLionel Sambuc 	*code = res = vbox_request(&hgcm_conn[conn].req[req].ptr->header,
164*433d6423SLionel Sambuc 		hgcm_conn[conn].req[req].addr, type, size);
165*433d6423SLionel Sambuc 
166*433d6423SLionel Sambuc 	r = convert_result(res);
167*433d6423SLionel Sambuc 
168*433d6423SLionel Sambuc 	if (r != OK && r != EDONTREPLY)
169*433d6423SLionel Sambuc 		return r;
170*433d6423SLionel Sambuc 
171*433d6423SLionel Sambuc 	/* The request may be processed either immediately or asynchronously.
172*433d6423SLionel Sambuc 	 * The caller of this function must be able to cope with both
173*433d6423SLionel Sambuc 	 * situations. In either case, mark the current request as ongoing.
174*433d6423SLionel Sambuc 	 */
175*433d6423SLionel Sambuc 	hgcm_conn[conn].req[req].busy = TRUE;
176*433d6423SLionel Sambuc 	hgcm_conn[conn].req[req].status = ipc_status;
177*433d6423SLionel Sambuc 	hgcm_conn[conn].req[req].id = id;
178*433d6423SLionel Sambuc 
179*433d6423SLionel Sambuc 	return r;
180*433d6423SLionel Sambuc }
181*433d6423SLionel Sambuc 
182*433d6423SLionel Sambuc /*===========================================================================*
183*433d6423SLionel Sambuc  *				cancel_req				     *
184*433d6423SLionel Sambuc  *===========================================================================*/
cancel_req(int conn,int req)185*433d6423SLionel Sambuc static void cancel_req(int conn, int req)
186*433d6423SLionel Sambuc {
187*433d6423SLionel Sambuc 	/* Cancel an ongoing request. */
188*433d6423SLionel Sambuc 
189*433d6423SLionel Sambuc 	assert(hgcm_conn[conn].req[req].ptr != NULL);
190*433d6423SLionel Sambuc 
191*433d6423SLionel Sambuc 	/* The cancel request consists only of the HGCM header. The physical
192*433d6423SLionel Sambuc 	 * location determines the request to cancel. Note that request
193*433d6423SLionel Sambuc 	 * cancellation this is full of race conditions, so we simply ignore
194*433d6423SLionel Sambuc 	 * the return value and assumed all went well.
195*433d6423SLionel Sambuc 	 */
196*433d6423SLionel Sambuc 	hgcm_conn[conn].req[req].ptr->flags = 0;
197*433d6423SLionel Sambuc 	hgcm_conn[conn].req[req].ptr->result = VMMDEV_ERR_GENERIC;
198*433d6423SLionel Sambuc 
199*433d6423SLionel Sambuc 	vbox_request(&hgcm_conn[conn].req[req].ptr->header,
200*433d6423SLionel Sambuc 		hgcm_conn[conn].req[req].addr, VMMDEV_REQ_HGCMCANCEL,
201*433d6423SLionel Sambuc 		sizeof(struct VMMDevHGCMCancel));
202*433d6423SLionel Sambuc 
203*433d6423SLionel Sambuc 	hgcm_conn[conn].req[req].busy = FALSE;
204*433d6423SLionel Sambuc }
205*433d6423SLionel Sambuc 
206*433d6423SLionel Sambuc /*===========================================================================*
207*433d6423SLionel Sambuc  *				finish_req				     *
208*433d6423SLionel Sambuc  *===========================================================================*/
finish_req(int conn,int req,int * code)209*433d6423SLionel Sambuc static int finish_req(int conn, int req, int *code)
210*433d6423SLionel Sambuc {
211*433d6423SLionel Sambuc 	/* The given request has finished. Take the appropriate action.
212*433d6423SLionel Sambuc 	 */
213*433d6423SLionel Sambuc 	struct VMMDevHGCMConnect *connreq;
214*433d6423SLionel Sambuc 	struct VMMDevHGCMCall *callreq;
215*433d6423SLionel Sambuc 	struct VMMDevHGCMParam *inp;
216*433d6423SLionel Sambuc 	vbox_param_t *outp;
217*433d6423SLionel Sambuc 	int i, count, res, r = OK;
218*433d6423SLionel Sambuc 
219*433d6423SLionel Sambuc 	hgcm_conn[conn].req[req].busy = FALSE;
220*433d6423SLionel Sambuc 
221*433d6423SLionel Sambuc 	*code = res = hgcm_conn[conn].req[req].ptr->result;
222*433d6423SLionel Sambuc 
223*433d6423SLionel Sambuc 	r = convert_result(res);
224*433d6423SLionel Sambuc 
225*433d6423SLionel Sambuc 	/* The request has finished, so it cannot still be in progress. */
226*433d6423SLionel Sambuc 	if (r == EDONTREPLY)
227*433d6423SLionel Sambuc 		r = EGENERIC;
228*433d6423SLionel Sambuc 
229*433d6423SLionel Sambuc 	switch (hgcm_conn[conn].state) {
230*433d6423SLionel Sambuc 	case STATE_FREE:
231*433d6423SLionel Sambuc 		assert(0);
232*433d6423SLionel Sambuc 
233*433d6423SLionel Sambuc 		break;
234*433d6423SLionel Sambuc 
235*433d6423SLionel Sambuc 	case STATE_OPENING:
236*433d6423SLionel Sambuc 		if (r == OK) {
237*433d6423SLionel Sambuc 			connreq = (struct VMMDevHGCMConnect *)
238*433d6423SLionel Sambuc 				hgcm_conn[conn].req[req].ptr;
239*433d6423SLionel Sambuc 			hgcm_conn[conn].client_id = connreq->client_id;
240*433d6423SLionel Sambuc 			hgcm_conn[conn].state = STATE_OPEN;
241*433d6423SLionel Sambuc 
242*433d6423SLionel Sambuc 			r = conn;
243*433d6423SLionel Sambuc 		} else {
244*433d6423SLionel Sambuc 			free_conn(conn);
245*433d6423SLionel Sambuc 		}
246*433d6423SLionel Sambuc 
247*433d6423SLionel Sambuc 		break;
248*433d6423SLionel Sambuc 
249*433d6423SLionel Sambuc 	case STATE_CLOSING:
250*433d6423SLionel Sambuc 		/* Neither we nor the caller can do anything with failures. */
251*433d6423SLionel Sambuc 		if (r != OK)
252*433d6423SLionel Sambuc 			printf("VBOX: disconnection failure #2 (%d)\n", res);
253*433d6423SLionel Sambuc 
254*433d6423SLionel Sambuc 		free_conn(conn);
255*433d6423SLionel Sambuc 
256*433d6423SLionel Sambuc 		r = OK;
257*433d6423SLionel Sambuc 
258*433d6423SLionel Sambuc 		break;
259*433d6423SLionel Sambuc 
260*433d6423SLionel Sambuc 	case STATE_OPEN:
261*433d6423SLionel Sambuc 		/* On success, extract and copy back parameters to the caller.
262*433d6423SLionel Sambuc 		 */
263*433d6423SLionel Sambuc 		if (r == OK) {
264*433d6423SLionel Sambuc 			callreq = (struct VMMDevHGCMCall *)
265*433d6423SLionel Sambuc 				hgcm_conn[conn].req[req].ptr;
266*433d6423SLionel Sambuc 			inp = (struct VMMDevHGCMParam *) &callreq[1];
267*433d6423SLionel Sambuc 			outp = &hgcm_conn[conn].req[req].param[0];
268*433d6423SLionel Sambuc 			count = hgcm_conn[conn].req[req].count;
269*433d6423SLionel Sambuc 
270*433d6423SLionel Sambuc 			for (i = 0; i < count; i++) {
271*433d6423SLionel Sambuc 				switch (outp->type) {
272*433d6423SLionel Sambuc 				case VBOX_TYPE_U32:
273*433d6423SLionel Sambuc 					outp->u32 = inp->u32;
274*433d6423SLionel Sambuc 					break;
275*433d6423SLionel Sambuc 
276*433d6423SLionel Sambuc 				case VBOX_TYPE_U64:
277*433d6423SLionel Sambuc 					outp->u64 = inp->u64;
278*433d6423SLionel Sambuc 					break;
279*433d6423SLionel Sambuc 
280*433d6423SLionel Sambuc 				default:
281*433d6423SLionel Sambuc 					break;
282*433d6423SLionel Sambuc 				}
283*433d6423SLionel Sambuc 
284*433d6423SLionel Sambuc 				inp++;
285*433d6423SLionel Sambuc 				outp++;
286*433d6423SLionel Sambuc 			}
287*433d6423SLionel Sambuc 
288*433d6423SLionel Sambuc 			if (count > 0) {
289*433d6423SLionel Sambuc 				r = sys_safecopyto(hgcm_conn[conn].endpt,
290*433d6423SLionel Sambuc 					hgcm_conn[conn].req[req].grant, 0,
291*433d6423SLionel Sambuc 					(vir_bytes)
292*433d6423SLionel Sambuc 					hgcm_conn[conn].req[req].param,
293*433d6423SLionel Sambuc 					count * sizeof(vbox_param_t));
294*433d6423SLionel Sambuc 			}
295*433d6423SLionel Sambuc 		}
296*433d6423SLionel Sambuc 
297*433d6423SLionel Sambuc 		break;
298*433d6423SLionel Sambuc 	}
299*433d6423SLionel Sambuc 
300*433d6423SLionel Sambuc 	return r;
301*433d6423SLionel Sambuc }
302*433d6423SLionel Sambuc 
303*433d6423SLionel Sambuc /*===========================================================================*
304*433d6423SLionel Sambuc  *				check_conn				     *
305*433d6423SLionel Sambuc  *===========================================================================*/
check_conn(int conn)306*433d6423SLionel Sambuc static void check_conn(int conn)
307*433d6423SLionel Sambuc {
308*433d6423SLionel Sambuc 	/* Check all requests for the given connection for completion. */
309*433d6423SLionel Sambuc 	int r, req, code;
310*433d6423SLionel Sambuc 
311*433d6423SLionel Sambuc 	for (req = 0; req < MAX_REQS; req++) {
312*433d6423SLionel Sambuc 		if (!hgcm_conn[conn].req[req].busy) continue;
313*433d6423SLionel Sambuc 
314*433d6423SLionel Sambuc 		if (!(hgcm_conn[conn].req[req].ptr->flags &
315*433d6423SLionel Sambuc 				VMMDEV_HGCM_REQ_DONE))
316*433d6423SLionel Sambuc 			continue;
317*433d6423SLionel Sambuc 
318*433d6423SLionel Sambuc 		r = finish_req(conn, req, &code);
319*433d6423SLionel Sambuc 
320*433d6423SLionel Sambuc 		assert(r != EDONTREPLY);
321*433d6423SLionel Sambuc 
322*433d6423SLionel Sambuc 		send_reply(hgcm_conn[conn].endpt,
323*433d6423SLionel Sambuc 			hgcm_conn[conn].req[req].status, r, code,
324*433d6423SLionel Sambuc 			hgcm_conn[conn].req[req].id);
325*433d6423SLionel Sambuc 	}
326*433d6423SLionel Sambuc }
327*433d6423SLionel Sambuc 
328*433d6423SLionel Sambuc /*===========================================================================*
329*433d6423SLionel Sambuc  *				do_open					     *
330*433d6423SLionel Sambuc  *===========================================================================*/
do_open(message * m_ptr,int ipc_status,int * code)331*433d6423SLionel Sambuc static int do_open(message *m_ptr, int ipc_status, int *code)
332*433d6423SLionel Sambuc {
333*433d6423SLionel Sambuc 	/* Process a connection request. */
334*433d6423SLionel Sambuc 	struct VMMDevHGCMConnect *connreq;
335*433d6423SLionel Sambuc 	int i, r, conn, count;
336*433d6423SLionel Sambuc 
337*433d6423SLionel Sambuc 	if (m_ptr->VBOX_COUNT < 0 || m_ptr->VBOX_COUNT > VMMDEV_HGCM_NAME_SIZE)
338*433d6423SLionel Sambuc 		return EINVAL;
339*433d6423SLionel Sambuc 
340*433d6423SLionel Sambuc 	/* Find a free connection slot. Make sure the sending endpoint is not
341*433d6423SLionel Sambuc 	 * already using up half of the connection slots.
342*433d6423SLionel Sambuc 	 */
343*433d6423SLionel Sambuc 	conn = -1;
344*433d6423SLionel Sambuc 	count = 0;
345*433d6423SLionel Sambuc 	for (i = 0; i < MAX_CONNS; i++) {
346*433d6423SLionel Sambuc 		if (conn < 0 && hgcm_conn[i].state == STATE_FREE)
347*433d6423SLionel Sambuc 			conn = i;
348*433d6423SLionel Sambuc 		if (hgcm_conn[i].endpt == m_ptr->m_source)
349*433d6423SLionel Sambuc 			count++;
350*433d6423SLionel Sambuc 	}
351*433d6423SLionel Sambuc 
352*433d6423SLionel Sambuc 	if (count >= MAX(MAX_CONNS / 2, 2))
353*433d6423SLionel Sambuc 		return EMFILE;
354*433d6423SLionel Sambuc 
355*433d6423SLionel Sambuc 	if (conn < 0)
356*433d6423SLionel Sambuc 		return ENFILE;
357*433d6423SLionel Sambuc 
358*433d6423SLionel Sambuc 	/* Initialize the connection and request structures. */
359*433d6423SLionel Sambuc 	hgcm_conn[conn].state = STATE_OPENING;
360*433d6423SLionel Sambuc 	hgcm_conn[conn].endpt = m_ptr->m_source;
361*433d6423SLionel Sambuc 
362*433d6423SLionel Sambuc 	for (i = 0; i < MAX_REQS; i++) {
363*433d6423SLionel Sambuc 		hgcm_conn[conn].req[i].busy = FALSE;
364*433d6423SLionel Sambuc 		hgcm_conn[conn].req[i].ptr = NULL;
365*433d6423SLionel Sambuc 	}
366*433d6423SLionel Sambuc 
367*433d6423SLionel Sambuc 	/* Set up and start the connection request. */
368*433d6423SLionel Sambuc 	r = alloc_req(conn);
369*433d6423SLionel Sambuc 
370*433d6423SLionel Sambuc 	if (r < 0)
371*433d6423SLionel Sambuc 		return r;
372*433d6423SLionel Sambuc 	assert(r == 0);
373*433d6423SLionel Sambuc 
374*433d6423SLionel Sambuc 	connreq = (struct VMMDevHGCMConnect *) hgcm_conn[conn].req[0].ptr;
375*433d6423SLionel Sambuc 	connreq->type = VMMDEV_HGCM_SVCLOC_LOCALHOST_EXISTING;
376*433d6423SLionel Sambuc 	if ((r = sys_safecopyfrom(m_ptr->m_source, m_ptr->VBOX_GRANT, 0,
377*433d6423SLionel Sambuc 			(vir_bytes) connreq->name, m_ptr->VBOX_COUNT)) !=
378*433d6423SLionel Sambuc 			OK) {
379*433d6423SLionel Sambuc 		free_conn(conn);
380*433d6423SLionel Sambuc 
381*433d6423SLionel Sambuc 		return r;
382*433d6423SLionel Sambuc 	}
383*433d6423SLionel Sambuc 	connreq->name[VMMDEV_HGCM_NAME_SIZE-1] = 0;
384*433d6423SLionel Sambuc 
385*433d6423SLionel Sambuc 	r = start_req(conn, 0, VMMDEV_REQ_HGCMCONNECT, sizeof(*connreq),
386*433d6423SLionel Sambuc 		ipc_status, m_ptr->VBOX_ID, code);
387*433d6423SLionel Sambuc 
388*433d6423SLionel Sambuc 	if (r != OK && r != EDONTREPLY) {
389*433d6423SLionel Sambuc 		free_conn(conn);
390*433d6423SLionel Sambuc 
391*433d6423SLionel Sambuc 		return r;
392*433d6423SLionel Sambuc 	}
393*433d6423SLionel Sambuc 
394*433d6423SLionel Sambuc 	return (r == OK) ? finish_req(conn, 0, code) : r;
395*433d6423SLionel Sambuc }
396*433d6423SLionel Sambuc 
397*433d6423SLionel Sambuc /*===========================================================================*
398*433d6423SLionel Sambuc  *				do_close				     *
399*433d6423SLionel Sambuc  *===========================================================================*/
do_close(message * m_ptr,int ipc_status,int * code)400*433d6423SLionel Sambuc static int do_close(message *m_ptr, int ipc_status, int *code)
401*433d6423SLionel Sambuc {
402*433d6423SLionel Sambuc 	/* Process a disconnection request. */
403*433d6423SLionel Sambuc 	struct VMMDevHGCMDisconnect *discreq;
404*433d6423SLionel Sambuc 	int r, conn, req;
405*433d6423SLionel Sambuc 
406*433d6423SLionel Sambuc 	conn = m_ptr->VBOX_CONN;
407*433d6423SLionel Sambuc 
408*433d6423SLionel Sambuc 	/* Sanity checks. */
409*433d6423SLionel Sambuc 	if (conn < 0 || conn >= MAX_CONNS)
410*433d6423SLionel Sambuc 		return EINVAL;
411*433d6423SLionel Sambuc 	if (hgcm_conn[conn].endpt != m_ptr->m_source ||
412*433d6423SLionel Sambuc 			hgcm_conn[conn].state != STATE_OPEN)
413*433d6423SLionel Sambuc 		return EINVAL;
414*433d6423SLionel Sambuc 
415*433d6423SLionel Sambuc 	/* Cancel any ongoing requests. */
416*433d6423SLionel Sambuc 	for (req = 0; req < MAX_REQS; req++)
417*433d6423SLionel Sambuc 		if (hgcm_conn[conn].req[req].busy)
418*433d6423SLionel Sambuc 			cancel_req(conn, req);
419*433d6423SLionel Sambuc 
420*433d6423SLionel Sambuc 	assert(hgcm_conn[conn].req[0].ptr != NULL);
421*433d6423SLionel Sambuc 
422*433d6423SLionel Sambuc 	discreq = (struct VMMDevHGCMDisconnect *) hgcm_conn[conn].req[0].ptr;
423*433d6423SLionel Sambuc 	discreq->client_id = hgcm_conn[conn].client_id;
424*433d6423SLionel Sambuc 
425*433d6423SLionel Sambuc 	r = start_req(conn, 0, VMMDEV_REQ_HGCMDISCONNECT, sizeof(*discreq),
426*433d6423SLionel Sambuc 		ipc_status, m_ptr->VBOX_ID, code);
427*433d6423SLionel Sambuc 
428*433d6423SLionel Sambuc 	if (r != OK && r != EDONTREPLY) {
429*433d6423SLionel Sambuc 		/* Neither we nor the caller can do anything with failures. */
430*433d6423SLionel Sambuc 		printf("VBOX: disconnection failure #1 (%d)\n", r);
431*433d6423SLionel Sambuc 
432*433d6423SLionel Sambuc 		free_conn(conn);
433*433d6423SLionel Sambuc 
434*433d6423SLionel Sambuc 		return OK;
435*433d6423SLionel Sambuc 	}
436*433d6423SLionel Sambuc 
437*433d6423SLionel Sambuc 	hgcm_conn[conn].state = STATE_CLOSING;
438*433d6423SLionel Sambuc 
439*433d6423SLionel Sambuc 	return (r == OK) ? finish_req(conn, 0, code) : r;
440*433d6423SLionel Sambuc }
441*433d6423SLionel Sambuc 
442*433d6423SLionel Sambuc /*===========================================================================*
443*433d6423SLionel Sambuc  *				store_pages				     *
444*433d6423SLionel Sambuc  *===========================================================================*/
store_pages(int conn,int req,vbox_param_t * inp,size_t * offp)445*433d6423SLionel Sambuc static int store_pages(int conn, int req, vbox_param_t *inp, size_t *offp)
446*433d6423SLionel Sambuc {
447*433d6423SLionel Sambuc 	/* Create a page list of physical pages that make up the provided
448*433d6423SLionel Sambuc 	 * buffer area.
449*433d6423SLionel Sambuc 	 */
450*433d6423SLionel Sambuc 	struct vumap_vir vvec;
451*433d6423SLionel Sambuc 	struct vumap_phys pvec[MAPVEC_NR];
452*433d6423SLionel Sambuc 	struct VMMDevHGCMPageList *pagelist;
453*433d6423SLionel Sambuc 	size_t offset, size, skip;
454*433d6423SLionel Sambuc 	int i, j, r, first, access, count, pages;
455*433d6423SLionel Sambuc 
456*433d6423SLionel Sambuc 	/* Empty strings are allowed. */
457*433d6423SLionel Sambuc 	if (inp->ptr.size == 0)
458*433d6423SLionel Sambuc 		return OK;
459*433d6423SLionel Sambuc 
460*433d6423SLionel Sambuc 	pagelist = (struct VMMDevHGCMPageList *)
461*433d6423SLionel Sambuc 		(((u8_t *) hgcm_conn[conn].req[req].ptr) + *offp);
462*433d6423SLionel Sambuc 
463*433d6423SLionel Sambuc 	pagelist->flags = 0;
464*433d6423SLionel Sambuc 	if (inp->ptr.dir & VBOX_DIR_IN)
465*433d6423SLionel Sambuc 		pagelist->flags |= VMMDEV_HGCM_FLAG_FROM_HOST;
466*433d6423SLionel Sambuc 	if (inp->ptr.dir & VBOX_DIR_OUT)
467*433d6423SLionel Sambuc 		pagelist->flags |= VMMDEV_HGCM_FLAG_TO_HOST;
468*433d6423SLionel Sambuc 	pagelist->count = 0;
469*433d6423SLionel Sambuc 
470*433d6423SLionel Sambuc 	/* Make sure there is room for the header (but no actual pages yet). */
471*433d6423SLionel Sambuc 	*offp += sizeof(*pagelist) - sizeof(pagelist->addr[0]);
472*433d6423SLionel Sambuc 	if (*offp > VMMDEV_BUF_SIZE)
473*433d6423SLionel Sambuc 		return ENOMEM;
474*433d6423SLionel Sambuc 
475*433d6423SLionel Sambuc 	access = 0;
476*433d6423SLionel Sambuc 	if (inp->ptr.dir & VBOX_DIR_IN) access |= VUA_WRITE;
477*433d6423SLionel Sambuc 	if (inp->ptr.dir & VBOX_DIR_OUT) access |= VUA_READ;
478*433d6423SLionel Sambuc 
479*433d6423SLionel Sambuc 	offset = 0;
480*433d6423SLionel Sambuc 	first = TRUE;
481*433d6423SLionel Sambuc 	do {
482*433d6423SLionel Sambuc 		/* If the caller gives us a huge buffer, we might need multiple
483*433d6423SLionel Sambuc 		 * calls to sys_vumap(). Note that the caller currently has no
484*433d6423SLionel Sambuc 		 * reliable way to know whether such a buffer will fit in our
485*433d6423SLionel Sambuc 		 * request page. In the future, we may dynamically reallocate
486*433d6423SLionel Sambuc 		 * the request area to make more room as necessary; for now we
487*433d6423SLionel Sambuc 		 * just return an ENOMEM error in such cases.
488*433d6423SLionel Sambuc 		 */
489*433d6423SLionel Sambuc 		vvec.vv_grant = inp->ptr.grant;
490*433d6423SLionel Sambuc 		vvec.vv_size = inp->ptr.off + inp->ptr.size;
491*433d6423SLionel Sambuc 		count = MAPVEC_NR;
492*433d6423SLionel Sambuc 		if ((r = sys_vumap(hgcm_conn[conn].endpt, &vvec, 1,
493*433d6423SLionel Sambuc 				inp->ptr.off + offset, access, pvec,
494*433d6423SLionel Sambuc 				&count)) != OK)
495*433d6423SLionel Sambuc 			return r;
496*433d6423SLionel Sambuc 
497*433d6423SLionel Sambuc 		/* First get the number of bytes processed, before (possibly)
498*433d6423SLionel Sambuc 		 * adjusting the size of the first element.
499*433d6423SLionel Sambuc 		 */
500*433d6423SLionel Sambuc 		for (i = size = 0; i < count; i++)
501*433d6423SLionel Sambuc 			size += pvec[i].vp_size;
502*433d6423SLionel Sambuc 
503*433d6423SLionel Sambuc 		/* VirtualBox wants aligned page addresses only, and an offset
504*433d6423SLionel Sambuc 		 * into the first page. All other pages except the last are
505*433d6423SLionel Sambuc 		 * full pages, and the last page is cut off using the size.
506*433d6423SLionel Sambuc 		 */
507*433d6423SLionel Sambuc 		skip = 0;
508*433d6423SLionel Sambuc 		if (first) {
509*433d6423SLionel Sambuc 			skip = pvec[0].vp_addr & (PAGE_SIZE - 1);
510*433d6423SLionel Sambuc 			pvec[0].vp_addr -= skip;
511*433d6423SLionel Sambuc 			pvec[0].vp_size += skip;
512*433d6423SLionel Sambuc 			pagelist->offset = skip;
513*433d6423SLionel Sambuc 			first = FALSE;
514*433d6423SLionel Sambuc 		}
515*433d6423SLionel Sambuc 
516*433d6423SLionel Sambuc 		/* How many pages were mapped? */
517*433d6423SLionel Sambuc 		pages = (skip + size + PAGE_SIZE - 1) / PAGE_SIZE;
518*433d6423SLionel Sambuc 
519*433d6423SLionel Sambuc 		/* Make sure there is room to store this many extra pages. */
520*433d6423SLionel Sambuc 		*offp += sizeof(pagelist->addr[0]) * pages;
521*433d6423SLionel Sambuc 		if (*offp > VMMDEV_BUF_SIZE)
522*433d6423SLionel Sambuc 			return ENOMEM;
523*433d6423SLionel Sambuc 
524*433d6423SLionel Sambuc 		/* Actually store the pages in the page list. */
525*433d6423SLionel Sambuc 		for (i = j = 0; i < pages; i++) {
526*433d6423SLionel Sambuc 			assert(!(pvec[j].vp_addr & (PAGE_SIZE - 1)));
527*433d6423SLionel Sambuc 
528*433d6423SLionel Sambuc 			pagelist->addr[pagelist->count++] =
529*433d6423SLionel Sambuc 				((u64_t)(pvec[j].vp_addr));
530*433d6423SLionel Sambuc 
531*433d6423SLionel Sambuc 			if (pvec[j].vp_size > PAGE_SIZE) {
532*433d6423SLionel Sambuc 				pvec[j].vp_addr += PAGE_SIZE;
533*433d6423SLionel Sambuc 				pvec[j].vp_size -= PAGE_SIZE;
534*433d6423SLionel Sambuc 			}
535*433d6423SLionel Sambuc 			else j++;
536*433d6423SLionel Sambuc 		}
537*433d6423SLionel Sambuc 		assert(j == count);
538*433d6423SLionel Sambuc 
539*433d6423SLionel Sambuc 		offset += size;
540*433d6423SLionel Sambuc 	} while (offset < inp->ptr.size);
541*433d6423SLionel Sambuc 
542*433d6423SLionel Sambuc 	assert(offset == inp->ptr.size);
543*433d6423SLionel Sambuc 
544*433d6423SLionel Sambuc 	return OK;
545*433d6423SLionel Sambuc }
546*433d6423SLionel Sambuc 
547*433d6423SLionel Sambuc /*===========================================================================*
548*433d6423SLionel Sambuc  *				do_call					     *
549*433d6423SLionel Sambuc  *===========================================================================*/
do_call(message * m_ptr,int ipc_status,int * code)550*433d6423SLionel Sambuc static int do_call(message *m_ptr, int ipc_status, int *code)
551*433d6423SLionel Sambuc {
552*433d6423SLionel Sambuc 	/* Perform a HGCM call. */
553*433d6423SLionel Sambuc 	vbox_param_t *inp;
554*433d6423SLionel Sambuc 	struct VMMDevHGCMParam *outp;
555*433d6423SLionel Sambuc 	struct VMMDevHGCMCall *callreq;
556*433d6423SLionel Sambuc 	size_t size;
557*433d6423SLionel Sambuc 	int i, r, conn, req, count;
558*433d6423SLionel Sambuc 
559*433d6423SLionel Sambuc 	conn = m_ptr->VBOX_CONN;
560*433d6423SLionel Sambuc 	count = m_ptr->VBOX_COUNT;
561*433d6423SLionel Sambuc 
562*433d6423SLionel Sambuc 	/* Sanity checks. */
563*433d6423SLionel Sambuc 	if (conn < 0 || conn >= MAX_CONNS)
564*433d6423SLionel Sambuc 		return EINVAL;
565*433d6423SLionel Sambuc 	if (hgcm_conn[conn].endpt != m_ptr->m_source ||
566*433d6423SLionel Sambuc 			hgcm_conn[conn].state != STATE_OPEN)
567*433d6423SLionel Sambuc 		return EINVAL;
568*433d6423SLionel Sambuc 
569*433d6423SLionel Sambuc 	/* Allocate a request, and copy in the parameters. */
570*433d6423SLionel Sambuc 	req = alloc_req(conn);
571*433d6423SLionel Sambuc 
572*433d6423SLionel Sambuc 	if (req < 0)
573*433d6423SLionel Sambuc 		return req;
574*433d6423SLionel Sambuc 
575*433d6423SLionel Sambuc 	hgcm_conn[conn].req[req].grant = m_ptr->VBOX_GRANT;
576*433d6423SLionel Sambuc 	hgcm_conn[conn].req[req].count = count;
577*433d6423SLionel Sambuc 
578*433d6423SLionel Sambuc 	if (count > 0) {
579*433d6423SLionel Sambuc 		if ((r = sys_safecopyfrom(m_ptr->m_source, m_ptr->VBOX_GRANT,
580*433d6423SLionel Sambuc 				0, (vir_bytes) hgcm_conn[conn].req[req].param,
581*433d6423SLionel Sambuc 				count * sizeof(vbox_param_t))) != OK)
582*433d6423SLionel Sambuc 			return r;
583*433d6423SLionel Sambuc 	}
584*433d6423SLionel Sambuc 
585*433d6423SLionel Sambuc 	/* Set up the basic request. */
586*433d6423SLionel Sambuc 	callreq = (struct VMMDevHGCMCall *) hgcm_conn[conn].req[req].ptr;
587*433d6423SLionel Sambuc 	callreq->client_id = hgcm_conn[conn].client_id;
588*433d6423SLionel Sambuc 	callreq->function = m_ptr->VBOX_FUNCTION;
589*433d6423SLionel Sambuc 	callreq->count = count;
590*433d6423SLionel Sambuc 
591*433d6423SLionel Sambuc 	/* Rewrite and convert the parameters. */
592*433d6423SLionel Sambuc 	inp = &hgcm_conn[conn].req[req].param[0];
593*433d6423SLionel Sambuc 	outp = (struct VMMDevHGCMParam *) &callreq[1];
594*433d6423SLionel Sambuc 
595*433d6423SLionel Sambuc 	size = sizeof(*callreq) + sizeof(*outp) * count;
596*433d6423SLionel Sambuc 	assert(size < VMMDEV_BUF_SIZE);
597*433d6423SLionel Sambuc 
598*433d6423SLionel Sambuc 	for (i = 0; i < count; i++) {
599*433d6423SLionel Sambuc 		switch (inp->type) {
600*433d6423SLionel Sambuc 		case VBOX_TYPE_U32:
601*433d6423SLionel Sambuc 			outp->type = VMMDEV_HGCM_PARAM_U32;
602*433d6423SLionel Sambuc 			outp->u32 = inp->u32;
603*433d6423SLionel Sambuc 			break;
604*433d6423SLionel Sambuc 
605*433d6423SLionel Sambuc 		case VBOX_TYPE_U64:
606*433d6423SLionel Sambuc 			outp->type = VMMDEV_HGCM_PARAM_U64;
607*433d6423SLionel Sambuc 			outp->u64 = inp->u64;
608*433d6423SLionel Sambuc 			break;
609*433d6423SLionel Sambuc 
610*433d6423SLionel Sambuc 		case VBOX_TYPE_PTR:
611*433d6423SLionel Sambuc 			outp->type = VMMDEV_HGCM_PARAM_PAGELIST;
612*433d6423SLionel Sambuc 			outp->pagelist.offset = size;
613*433d6423SLionel Sambuc 			outp->pagelist.size = inp->ptr.size;
614*433d6423SLionel Sambuc 
615*433d6423SLionel Sambuc 			if ((r = store_pages(conn, req, inp, &size)) != OK)
616*433d6423SLionel Sambuc 				return r;
617*433d6423SLionel Sambuc 
618*433d6423SLionel Sambuc 			break;
619*433d6423SLionel Sambuc 
620*433d6423SLionel Sambuc 		default:
621*433d6423SLionel Sambuc 			return EINVAL;
622*433d6423SLionel Sambuc 		}
623*433d6423SLionel Sambuc 
624*433d6423SLionel Sambuc 		inp++;
625*433d6423SLionel Sambuc 		outp++;
626*433d6423SLionel Sambuc 	}
627*433d6423SLionel Sambuc 
628*433d6423SLionel Sambuc 	/* Start the request. */
629*433d6423SLionel Sambuc 	r = start_req(conn, req, VMMDEV_REQ_HGCMCALL, size, ipc_status,
630*433d6423SLionel Sambuc 		m_ptr->VBOX_ID, code);
631*433d6423SLionel Sambuc 
632*433d6423SLionel Sambuc 	if (r != OK && r != EDONTREPLY)
633*433d6423SLionel Sambuc 		return r;
634*433d6423SLionel Sambuc 
635*433d6423SLionel Sambuc 	return (r == OK) ? finish_req(conn, req, code) : r;
636*433d6423SLionel Sambuc }
637*433d6423SLionel Sambuc 
638*433d6423SLionel Sambuc /*===========================================================================*
639*433d6423SLionel Sambuc  *				do_cancel				     *
640*433d6423SLionel Sambuc  *===========================================================================*/
do_cancel(message * m_ptr,int ipc_status)641*433d6423SLionel Sambuc static int do_cancel(message *m_ptr, int ipc_status)
642*433d6423SLionel Sambuc {
643*433d6423SLionel Sambuc 	/* Cancel an ongoing call. */
644*433d6423SLionel Sambuc 	int conn, req;
645*433d6423SLionel Sambuc 
646*433d6423SLionel Sambuc 	conn = m_ptr->VBOX_CONN;
647*433d6423SLionel Sambuc 
648*433d6423SLionel Sambuc 	/* Sanity checks. Note that connection and disconnection requests
649*433d6423SLionel Sambuc 	 * cannot be cancelled.
650*433d6423SLionel Sambuc 	 */
651*433d6423SLionel Sambuc 	if (conn < 0 || conn >= MAX_CONNS)
652*433d6423SLionel Sambuc 		return EINVAL;
653*433d6423SLionel Sambuc 	if (hgcm_conn[conn].endpt != m_ptr->m_source ||
654*433d6423SLionel Sambuc 			hgcm_conn[conn].state != STATE_OPEN)
655*433d6423SLionel Sambuc 		return EINVAL;
656*433d6423SLionel Sambuc 
657*433d6423SLionel Sambuc 	/* Find the request. */
658*433d6423SLionel Sambuc 	for (req = 0; req < MAX_REQS; req++) {
659*433d6423SLionel Sambuc 		if (hgcm_conn[conn].req[req].busy &&
660*433d6423SLionel Sambuc 				hgcm_conn[conn].req[req].id == m_ptr->VBOX_ID)
661*433d6423SLionel Sambuc 			break;
662*433d6423SLionel Sambuc 	}
663*433d6423SLionel Sambuc 
664*433d6423SLionel Sambuc 	/* If no such request was ongoing, then our behavior depends on the
665*433d6423SLionel Sambuc 	 * way the request was made: we do not want to send two asynchronous
666*433d6423SLionel Sambuc 	 * replies for one request, but if the caller used SENDREC, we have to
667*433d6423SLionel Sambuc 	 * reply with something or the caller would deadlock.
668*433d6423SLionel Sambuc 	 */
669*433d6423SLionel Sambuc 	if (req == MAX_REQS) {
670*433d6423SLionel Sambuc 		if (IPC_STATUS_CALL(ipc_status) == SENDREC)
671*433d6423SLionel Sambuc 			return EINVAL;
672*433d6423SLionel Sambuc 		else
673*433d6423SLionel Sambuc 			return EDONTREPLY;
674*433d6423SLionel Sambuc 	}
675*433d6423SLionel Sambuc 
676*433d6423SLionel Sambuc 	/* Actually cancel the request, and send a reply. */
677*433d6423SLionel Sambuc 	cancel_req(conn, req);
678*433d6423SLionel Sambuc 
679*433d6423SLionel Sambuc 	return EINTR;
680*433d6423SLionel Sambuc }
681*433d6423SLionel Sambuc 
682*433d6423SLionel Sambuc /*===========================================================================*
683*433d6423SLionel Sambuc  *				hgcm_message				     *
684*433d6423SLionel Sambuc  *===========================================================================*/
hgcm_message(message * m_ptr,int ipc_status)685*433d6423SLionel Sambuc void hgcm_message(message *m_ptr, int ipc_status)
686*433d6423SLionel Sambuc {
687*433d6423SLionel Sambuc 	/* Process a request message. */
688*433d6423SLionel Sambuc 	int r, code = VMMDEV_ERR_GENERIC;
689*433d6423SLionel Sambuc 
690*433d6423SLionel Sambuc 	switch (m_ptr->m_type) {
691*433d6423SLionel Sambuc 	case VBOX_OPEN:		r = do_open(m_ptr, ipc_status, &code);	break;
692*433d6423SLionel Sambuc 	case VBOX_CLOSE:	r = do_close(m_ptr, ipc_status, &code);	break;
693*433d6423SLionel Sambuc 	case VBOX_CALL:		r = do_call(m_ptr, ipc_status, &code);	break;
694*433d6423SLionel Sambuc 	case VBOX_CANCEL:	r = do_cancel(m_ptr, ipc_status);	break;
695*433d6423SLionel Sambuc 	default:		r = ENOSYS;				break;
696*433d6423SLionel Sambuc 	}
697*433d6423SLionel Sambuc 
698*433d6423SLionel Sambuc 	if (r != EDONTREPLY)
699*433d6423SLionel Sambuc 		send_reply(m_ptr->m_source, ipc_status, r, code,
700*433d6423SLionel Sambuc 			m_ptr->VBOX_ID);
701*433d6423SLionel Sambuc }
702*433d6423SLionel Sambuc 
703*433d6423SLionel Sambuc /*===========================================================================*
704*433d6423SLionel Sambuc  *				hgcm_intr				     *
705*433d6423SLionel Sambuc  *===========================================================================*/
hgcm_intr(void)706*433d6423SLionel Sambuc void hgcm_intr(void)
707*433d6423SLionel Sambuc {
708*433d6423SLionel Sambuc 	/* We received an HGCM event. Check ongoing requests for completion. */
709*433d6423SLionel Sambuc 	int conn;
710*433d6423SLionel Sambuc 
711*433d6423SLionel Sambuc 	for (conn = 0; conn < MAX_CONNS; conn++)
712*433d6423SLionel Sambuc 		if (hgcm_conn[conn].state != STATE_FREE)
713*433d6423SLionel Sambuc 			check_conn(conn);
714*433d6423SLionel Sambuc }
715