xref: /minix/minix/lib/libsys/arch/i386/vbox.c (revision e3b78ef1)
1 /* VBOX driver interface - synchronous version - by D.C. van Moolenbroek */
2 
3 #include <minix/drivers.h>
4 #include <minix/vboxtype.h>
5 #include <minix/vboxif.h>
6 #include <minix/vbox.h>
7 #include <minix/ds.h>
8 #include <assert.h>
9 
10 static endpoint_t vbox_endpt = NONE;
11 
12 int vbox_init(void)
13 {
14 /* Initialize the library, by resolving the VBOX driver endpoint.
15  */
16   int r;
17 
18   if ((r = ds_retrieve_label_endpt("vbox", &vbox_endpt)) != OK) {
19 	printf("libvbox: unable to obtain VBOX endpoint (%d)\n", r);
20 
21 	return EINVAL;
22   }
23 
24   return OK;
25 }
26 
27 vbox_conn_t vbox_open(const char *name)
28 {
29 /* Open a VirtualBox HGCM connection.
30  */
31   message m;
32   cp_grant_id_t grant;
33   size_t len;
34   int r;
35 
36   if (vbox_endpt == NONE)
37 	return EDEADSRCDST;
38 
39   len = strlen(name) + 1;
40   grant = cpf_grant_direct(vbox_endpt, (vir_bytes) name, len, CPF_READ);
41   if (!GRANT_VALID(grant))
42 	return ENOMEM;
43 
44   memset(&m, 0, sizeof(m));
45   m.m_type = VBOX_OPEN;
46   m.VBOX_GRANT = grant;
47   m.VBOX_COUNT = len;
48   m.VBOX_ID = 0;
49 
50   r = ipc_sendrec(vbox_endpt, &m);
51 
52   cpf_revoke(grant);
53 
54   if (r != OK)
55 	return r;
56 
57   if (m.VBOX_ID != 0)
58 	return EINVAL;
59 
60   return m.VBOX_RESULT;
61 }
62 
63 int vbox_close(vbox_conn_t conn)
64 {
65 /* Close a VirtualBox HGCM connection.
66  */
67   message m;
68   int r;
69 
70   if (vbox_endpt == NONE)
71 	return EDEADSRCDST;
72 
73   memset(&m, 0, sizeof(m));
74   m.m_type = VBOX_CLOSE;
75   m.VBOX_CONN = conn;
76   m.VBOX_ID = 0;
77 
78   r = ipc_sendrec(vbox_endpt, &m);
79 
80   if (r != OK)
81 	return r;
82 
83   if (m.VBOX_ID != 0)
84 	return EINVAL;
85 
86   return m.VBOX_RESULT;
87 }
88 
89 int vbox_call(vbox_conn_t conn, u32_t function, vbox_param_t *param, int count,
90   int *code)
91 {
92 /* Call a VirtualBox HGCM function. The caller must set up all buffer grants.
93  */
94   cp_grant_id_t grant = GRANT_INVALID;
95   message m;
96   int i, r;
97 
98   if (vbox_endpt == NONE) {
99 	vbox_put(param, count);
100 
101 	return EDEADSRCDST;
102   }
103 
104   /* Check whether all parameters are initialized correctly. */
105   for (i = 0; i < count; i++) {
106 	switch (param[i].type) {
107 	case VBOX_TYPE_U32:
108 	case VBOX_TYPE_U64:
109 	case VBOX_TYPE_PTR:
110 		break;
111 
112 	default:
113 		vbox_put(param, count);
114 
115 		return ENOMEM;
116 	}
117   }
118 
119   if (count > 0) {
120 	grant = cpf_grant_direct(vbox_endpt, (vir_bytes) param,
121 		sizeof(param[0]) * count, CPF_READ | CPF_WRITE);
122 	if (!GRANT_VALID(grant)) {
123 		vbox_put(param, count);
124 
125 		return ENOMEM;
126 	}
127   }
128 
129   memset(&m, 0, sizeof(m));
130   m.m_type = VBOX_CALL;
131   m.VBOX_CONN = conn;
132   m.VBOX_GRANT = grant;
133   m.VBOX_COUNT = count;
134   m.VBOX_ID = 0;
135   m.VBOX_FUNCTION = function;
136 
137   r = ipc_sendrec(vbox_endpt, &m);
138 
139   if (GRANT_VALID(grant))
140 	cpf_revoke(grant);
141 
142   vbox_put(param, count);
143 
144   if (r != OK)
145 	return r;
146 
147   if (m.VBOX_ID != 0)
148 	return EINVAL;
149 
150   if (code != NULL)
151 	*code = m.VBOX_CODE;
152 
153   return m.VBOX_RESULT;
154 }
155 
156 void vbox_set_u32(vbox_param_t *param, u32_t value)
157 {
158 /* Set the given parameter to a 32-bit value.
159  */
160 
161   param->type = VBOX_TYPE_U32;
162   param->u32 = value;
163 }
164 
165 void vbox_set_u64(vbox_param_t *param, u64_t value)
166 {
167 /* Set the given parameter to a 32-bit value.
168  */
169 
170   param->type = VBOX_TYPE_U64;
171   param->u64 = value;
172 }
173 
174 void vbox_set_ptr(vbox_param_t *param, void *ptr, size_t size,
175   unsigned int dir)
176 {
177 /* Set the given parameter to a grant for the given local pointer.
178  */
179   cp_grant_id_t grant = GRANT_INVALID;
180   int flags;
181 
182   flags = 0;
183   if (dir & VBOX_DIR_IN) flags |= CPF_WRITE;
184   if (dir & VBOX_DIR_OUT) flags |= CPF_READ;
185 
186   if (size > 0) {
187 	grant = cpf_grant_direct(vbox_endpt, (vir_bytes) ptr, size, flags);
188 	if (!GRANT_VALID(grant)) {
189 		param->type = VBOX_TYPE_INVALID;
190 
191 		return;
192 	}
193   }
194 
195   param->type = VBOX_TYPE_PTR;
196   param->ptr.grant = grant;
197   param->ptr.off = 0;
198   param->ptr.size = size;
199   param->ptr.dir = dir;
200 }
201 
202 void vbox_set_grant(vbox_param_t *param, endpoint_t endpt, cp_grant_id_t grant,
203   size_t off, size_t size, unsigned int dir)
204 {
205 /* Set the given parameter to an indirect grant for the given grant.
206  */
207   cp_grant_id_t indir_grant;
208 
209   /* Unfortunately, the current implementation of indirect grants does not
210    * support making smaller subgrants out of larger original grants. Therefore,
211    * we are forced to grant more access than we would like.
212    */
213   indir_grant = cpf_grant_indirect(vbox_endpt, endpt, grant);
214   if (!GRANT_VALID(indir_grant)) {
215 	param->type = VBOX_TYPE_INVALID;
216 
217 	return;
218   }
219 
220   param->type = VBOX_TYPE_PTR;
221   param->ptr.grant = indir_grant;
222   param->ptr.off = off;
223   param->ptr.size = size;
224   param->ptr.dir = dir;
225 }
226 
227 void vbox_put(vbox_param_t *param, int count)
228 {
229 /* Free all resources used for the given parameters.
230  */
231 
232   while (count--) {
233 	if (param->type == VBOX_TYPE_PTR && GRANT_VALID(param->ptr.grant))
234 		cpf_revoke(param->ptr.grant);
235 
236 	param++;
237   }
238 }
239 
240 u32_t vbox_get_u32(vbox_param_t *param)
241 {
242 /* Retrieve the 32-bit value from the given parameter.
243  */
244 
245   assert(param->type == VBOX_TYPE_U32);
246   return param->u32;
247 }
248 
249 u64_t vbox_get_u64(vbox_param_t *param)
250 {
251 /* Retrieve the 64-bit value from the given parameter.
252  */
253 
254   assert(param->type == VBOX_TYPE_U64);
255   return param->u64;
256 }
257