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
vbox_init(void)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
vbox_open(const char * name)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
vbox_close(vbox_conn_t conn)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
vbox_call(vbox_conn_t conn,u32_t function,vbox_param_t * param,int count,int * code)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
vbox_set_u32(vbox_param_t * param,u32_t value)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
vbox_set_u64(vbox_param_t * param,u64_t value)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
vbox_set_ptr(vbox_param_t * param,void * ptr,size_t size,unsigned int dir)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
vbox_set_grant(vbox_param_t * param,endpoint_t endpt,cp_grant_id_t grant,size_t off,size_t size,unsigned int dir)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
vbox_put(vbox_param_t * param,int count)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
vbox_get_u32(vbox_param_t * param)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
vbox_get_u64(vbox_param_t * param)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