30 |
|
|
31 |
#include "ipc-kmsg.h" |
#include "ipc-kmsg.h" |
32 |
|
|
33 |
#ifndef WORD_ALIGN |
/* Notes about the message intermediate format: |
34 |
|
|
35 |
|
Port names are resolved into pointers to port structures (ie ipc_port). |
36 |
|
Out-of-line memory is held by a holding map if it not maps against |
37 |
|
port rights. If it do, hold a kernel buffer with port structures. */ |
38 |
|
|
39 |
|
#ifndef WORD_ALIGN /* ??? move to tm.h */ |
40 |
# define WORD_ALIGN(X) (((X) + 3) & ~3) |
# define WORD_ALIGN(X) (((X) + 3) & ~3) |
41 |
#endif |
#endif |
42 |
|
|
168 |
return KERN_SUCCESS; |
return KERN_SUCCESS; |
169 |
} |
} |
170 |
|
|
171 |
|
|
172 |
|
|
173 |
|
/* Convert kernel message in KMSG to intermediate format stored on |
174 |
|
the message queue. Ports names are resolved into ports, and |
175 |
|
out-of-line memory is held by a holding map. */ |
176 |
|
kern_return_t |
177 |
|
convert_kernel_to_intermediate (struct ipc_kmsg *kmsg) |
178 |
|
{ |
179 |
|
struct rtmk_msg_type_long *type_long; |
180 |
|
struct rtmk_msg_type *type; |
181 |
|
vm_offset_t start, end; |
182 |
|
|
183 |
|
start = (vm_offset_t) (&kmsg->header + 1); |
184 |
|
end = ((vm_offset_t) (&kmsg->header)) + kmsg->header.msgh_length; |
185 |
|
|
186 |
|
/* Loop through all type elements of the message body. */ |
187 |
|
|
188 |
|
while (start < end) |
189 |
|
{ |
190 |
|
unsigned int header_size, number, length, size; |
191 |
|
vm_offset_t data_ptr; |
192 |
|
|
193 |
|
/* If we we have a long format message type header we |
194 |
|
get length and number fields from long structure. */ |
195 |
|
type = (struct rtmk_msg_type *) start; |
196 |
|
size = type->msgt_length; |
197 |
|
|
198 |
|
if (LIKELY (! type->msgt_long)) |
199 |
|
{ |
200 |
|
header_size = sizeof (struct rtmk_msg_type); |
201 |
|
number = type->msgt_number; |
202 |
|
} |
203 |
|
else |
204 |
|
{ |
205 |
|
type_long = (struct rtmk_msg_type_long *) type; |
206 |
|
header_size = sizeof (struct rtmk_msg_type_long); |
207 |
|
number = type_long->msgtl_number; |
208 |
|
} |
209 |
|
|
210 |
|
/* DATA_PTR points to where the inline data begins. */ |
211 |
|
data_ptr = ((vm_offset_t) type) + header_size; |
212 |
|
|
213 |
|
/* Calulcate length of data (either inline or out-of-line). */ |
214 |
|
length = ((number * size) + 7) >> 3; |
215 |
|
|
216 |
|
/* For out-of-line memory we create a holding map and store |
217 |
|
it in the position for the data pointer. */ |
218 |
|
if (! type->msgt_inline) |
219 |
|
{ |
220 |
|
/* The sender should supply ready-made memory |
221 |
|
for us, so we don't need to do anything. */ |
222 |
|
} |
223 |
|
|
224 |
|
/* Calulcat length of inline data and skip over it. */ |
225 |
|
if (LIKELY (type->msgt_inline)) |
226 |
|
start = WORD_ALIGN (data_ptr + length); |
227 |
|
else |
228 |
|
start = data_ptr + sizeof (rtmk_port_t *); /* ??? ptr */ |
229 |
|
} |
230 |
|
return KERN_SUCCESS; |
231 |
|
} |
232 |
|
|
233 |
|
|
234 |
|
/* Convert user message in KMSG to intermediate format stored on |
235 |
|
the message queue. Ports names are resolved into ports, and |
236 |
|
out-of-line memory is held by a holding map. */ |
237 |
|
kern_return_t |
238 |
|
convert_user_to_intermediate (struct task *task, struct ipc_kmsg *kmsg) |
239 |
|
{ |
240 |
|
struct rtmk_msg_type_long *type_long; |
241 |
|
struct rtmk_msg_type *type; |
242 |
|
vm_offset_t start, end; |
243 |
|
kern_return_t kr; |
244 |
|
|
245 |
|
start = (vm_offset_t) (&kmsg->header + 1); |
246 |
|
end = ((vm_offset_t) (&kmsg->header)) + kmsg->header.msgh_length; |
247 |
|
|
248 |
|
/* Loop through all type elements of the message body. */ |
249 |
|
|
250 |
|
while (start < end) |
251 |
|
{ |
252 |
|
unsigned int header_size, number, length, size, port_p, i; |
253 |
|
struct ipc_entry *entry; |
254 |
|
vm_offset_t data_ptr; |
255 |
|
|
256 |
|
/* If we we have a long format message type header we |
257 |
|
get length and number fields from long structure. */ |
258 |
|
type = (struct rtmk_msg_type *) start; |
259 |
|
size = type->msgt_length; |
260 |
|
|
261 |
|
if (LIKELY (! type->msgt_long)) |
262 |
|
{ |
263 |
|
header_size = sizeof (struct rtmk_msg_type); |
264 |
|
number = type->msgt_number; |
265 |
|
} |
266 |
|
else |
267 |
|
{ |
268 |
|
type_long = (struct rtmk_msg_type_long *) type; |
269 |
|
header_size = sizeof (struct rtmk_msg_type_long); |
270 |
|
number = type_long->msgtl_number; |
271 |
|
} |
272 |
|
|
273 |
|
/* DATA_PTR points to where the inline data begins. */ |
274 |
|
data_ptr = ((vm_offset_t) type) + header_size; |
275 |
|
|
276 |
|
/* Calulcate length of data (either inline or out-of-line). */ |
277 |
|
length = ((number * size) + 7) >> 3; |
278 |
|
|
279 |
|
port_p = RTMK_MSG_TYPE_PORT_ANY (type->msgt_type); |
280 |
|
|
281 |
|
/* ??? it is very likely that it's inline data. */ |
282 |
|
if (LIKELY (type->msgt_inline)) |
283 |
|
{ |
284 |
|
if (port_p) |
285 |
|
{ |
286 |
|
rtmk_port_t *port_name; |
287 |
|
struct ipc_port *port; |
288 |
|
|
289 |
|
port_name = (rtmk_port_t *) data_ptr; |
290 |
|
|
291 |
|
/* Loop through all elements and take actions upon them. */ |
292 |
|
for (i = 0; i < number; i++) |
293 |
|
{ |
294 |
|
if (port_name [i]) |
295 |
|
{ |
296 |
|
/* ??? not lookup, do copyin */ |
297 |
|
kr = ipc_object_lookup (task->ipc_object, port_name [i], |
298 |
|
& entry); |
299 |
|
if (kr != KERN_SUCCESS) |
300 |
|
return kr; |
301 |
|
|
302 |
|
port = entry->ie_port; |
303 |
|
} |
304 |
|
else |
305 |
|
port = 0; |
306 |
|
|
307 |
|
/* Store pointer to port structure in place for port name. */ |
308 |
|
port_name [i] = (rtmk_port_t) port; |
309 |
|
} |
310 |
|
} |
311 |
|
} |
312 |
|
|
313 |
|
/* Out-of-line memory: */ |
314 |
|
else |
315 |
|
{ |
316 |
|
if (port_p) |
317 |
|
{ |
318 |
|
struct ipc_port **ports, *port; |
319 |
|
rtmk_port_t *port_name; |
320 |
|
|
321 |
|
/* We allocate a internal buffer for the port structures. |
322 |
|
We copy in user data from address space into that buffer. */ |
323 |
|
ports = (struct ipc_port **) kmem_malloc (length); |
324 |
|
COPYIN ((void *) ports, *(void **) data_ptr, length); |
325 |
|
|
326 |
|
port_name = (rtmk_port_t *) ports; |
327 |
|
|
328 |
|
/* Loop through all port names and take actions. */ |
329 |
|
for (i = 0; i < number; i++) |
330 |
|
{ |
331 |
|
if (port_name [i]) |
332 |
|
{ |
333 |
|
kr = ipc_object_lookup (task->ipc_object, port_name [i], |
334 |
|
& entry); |
335 |
|
if (kr != KERN_SUCCESS) |
336 |
|
return kr; |
337 |
|
port = entry->ie_port; |
338 |
|
} |
339 |
|
else |
340 |
|
port = 0; |
341 |
|
|
342 |
|
/* Store pointer to port structure in place for port name. */ |
343 |
|
port_name [i] = (rtmk_port_t) port; |
344 |
|
} |
345 |
|
} |
346 |
|
|
347 |
|
/* For out-of-line memory we create a holding map and store |
348 |
|
it in the position for the data pointer. */ |
349 |
|
else |
350 |
|
{ |
351 |
|
struct vm_map *map; |
352 |
|
|
353 |
|
if (length != 0) |
354 |
|
{ |
355 |
|
map = vm_map_copyin (task->map, *(vm_offset_t *) data_ptr, |
356 |
|
length, type->msgt_deallocate); |
357 |
|
assert (map); |
358 |
|
*(vm_offset_t *) data_ptr = (vm_offset_t) map; |
359 |
|
} |
360 |
|
} |
361 |
|
} |
362 |
|
|
363 |
|
/* Calulcat length of inline data and skip over it. */ |
364 |
|
if (LIKELY (type->msgt_inline)) |
365 |
|
start = WORD_ALIGN (data_ptr + length); |
366 |
|
else |
367 |
|
start = data_ptr + sizeof (rtmk_port_t *); /* ??? ptr */ |
368 |
|
} |
369 |
|
return KERN_SUCCESS; |
370 |
|
} |
371 |
|
|
372 |
|
|
373 |
|
|
374 |
|
/* Convert intermediate message stored in KMSG to user format |
375 |
|
where ports is translated into port names and out-of-line memory |
376 |
|
is mapped into TASK's address space. */ |
377 |
|
kern_return_t |
378 |
|
convert_intermediate_to_user (struct task *task, struct ipc_kmsg *kmsg) |
379 |
|
{ |
380 |
|
struct rtmk_msg_type_long *type_long; |
381 |
|
struct rtmk_msg_type *type; |
382 |
|
vm_offset_t start, end; |
383 |
|
kern_return_t kr; |
384 |
|
|
385 |
|
start = (vm_offset_t) (&kmsg->header + 1); |
386 |
|
end = ((vm_offset_t) (&kmsg->header)) + kmsg->header.msgh_length; |
387 |
|
|
388 |
|
/* Loop through all type elements of the message body. */ |
389 |
|
|
390 |
|
while (start < end) |
391 |
|
{ |
392 |
|
unsigned int header_size, number, length, size, port_p, i; |
393 |
|
vm_offset_t data_ptr; |
394 |
|
|
395 |
|
/* If we we have a long format message type header we |
396 |
|
get length and number fields from long structure. */ |
397 |
|
type = (struct rtmk_msg_type *) start; |
398 |
|
size = type->msgt_length; |
399 |
|
|
400 |
|
if (LIKELY (! type->msgt_long)) |
401 |
|
{ |
402 |
|
header_size = sizeof (struct rtmk_msg_type); |
403 |
|
number = type->msgt_number; |
404 |
|
} |
405 |
|
else |
406 |
|
{ |
407 |
|
type_long = (struct rtmk_msg_type_long *) type; |
408 |
|
header_size = sizeof (struct rtmk_msg_type_long); |
409 |
|
number = type_long->msgtl_number; |
410 |
|
} |
411 |
|
|
412 |
|
/* DATA_PTR points to where the inline data begins. */ |
413 |
|
data_ptr = ((vm_offset_t) type) + header_size; |
414 |
|
|
415 |
|
/* Calulcate length of data (either inline or out-of-line). */ |
416 |
|
length = ((number * size) + 7) >> 3; |
417 |
|
|
418 |
|
port_p = RTMK_MSG_TYPE_PORT_ANY (type->msgt_type); |
419 |
|
|
420 |
|
if (LIKELY (type->msgt_inline)) |
421 |
|
{ |
422 |
|
if (port_p) |
423 |
|
{ |
424 |
|
struct ipc_port **port; |
425 |
|
rtmk_port_t *port_name; |
426 |
|
|
427 |
|
/* ??? ports can not be in out-of-line memory? */ |
428 |
|
assert (type->msgt_inline == true); |
429 |
|
|
430 |
|
port_name = (rtmk_port_t *) data_ptr; |
431 |
|
port = (struct ipc_port **) data_ptr; |
432 |
|
|
433 |
|
/* Loop through all elements and take actions upon them. */ |
434 |
|
for (i = 0; i < number; i++) |
435 |
|
{ |
436 |
|
if (port [i]) |
437 |
|
{ |
438 |
|
kr = ipc_object_copyout (task->ipc_object, port [i], |
439 |
|
type->msgt_type, |
440 |
|
& port_name [i]); |
441 |
|
if (kr != KERN_SUCCESS) |
442 |
|
return kr; |
443 |
|
} |
444 |
|
else |
445 |
|
port_name [i] = RTMK_PORT_NULL; |
446 |
|
} |
447 |
|
} |
448 |
|
} |
449 |
|
|
450 |
|
/* For out-of-line memory we create a holding map and store |
451 |
|
it in the position for the data pointer. */ |
452 |
|
else |
453 |
|
{ |
454 |
|
/* If the out-of-line is port rights, the ports is held |
455 |
|
by a kernel buffer stored at *DATA_PTR. */ |
456 |
|
if (port_p) |
457 |
|
{ |
458 |
|
struct ipc_port **port = *(struct ipc_port ***) data_ptr; |
459 |
|
rtmk_port_t *port_name = *(rtmk_port_t **) data_ptr; |
460 |
|
vm_offset_t addr; |
461 |
|
|
462 |
|
/* Loop through all elements and take actions upon them. */ |
463 |
|
for (i = 0; i < number; i++) |
464 |
|
{ |
465 |
|
if (port [i]) |
466 |
|
{ |
467 |
|
kr = ipc_object_copyout (task->ipc_object, port [i], |
468 |
|
type->msgt_type, |
469 |
|
& port_name [i]); |
470 |
|
if (kr != KERN_SUCCESS) |
471 |
|
return kr; |
472 |
|
} |
473 |
|
} |
474 |
|
|
475 |
|
/* Here: Port names are in PORT_NAME. What we need to do; |
476 |
|
allocate memory in TASK's addres space and copy out. */ |
477 |
|
kr = vm_map_allocate (task->map, & addr, vm_round_page (length), |
478 |
|
0, VM_PROT_ALL, VM_PROT_ALL, |
479 |
|
VM_INHERIT_COPY, 1); |
480 |
|
assert (kr == KERN_SUCCESS); |
481 |
|
|
482 |
|
COPYOUT ((void *) addr, (void *) port_name, length); |
483 |
|
*(vm_offset_t *) data_ptr = addr; |
484 |
|
|
485 |
|
kmem_mfree (port); |
486 |
|
} |
487 |
|
else |
488 |
|
{ |
489 |
|
assert (0); |
490 |
|
} |
491 |
|
} |
492 |
|
|
493 |
|
/* Calulcat length of inline data and skip over it. */ |
494 |
|
if (LIKELY (type->msgt_inline)) |
495 |
|
start = WORD_ALIGN (data_ptr + length); |
496 |
|
else |
497 |
|
start = data_ptr + sizeof (vm_offset_t); |
498 |
|
} |
499 |
|
return KERN_SUCCESS; |
500 |
|
} |
501 |
|
|
502 |
/* Convert message stored in KMSG to intermedate format where port |
/* Convert message stored in KMSG to intermedate format where port |
503 |
names are resolved to ipc_port structures and out-of-line data |
names are resolved to ipc_port structures and out-of-line data |
504 |
in mapped into kernel address space. */ |
in mapped into kernel address space. */ |
726 |
if (kr) |
if (kr) |
727 |
return kr; |
return kr; |
728 |
|
|
729 |
kr = copyout_body (task, kmsg); |
kr = convert_intermediate_to_user (task, kmsg); |
730 |
if (kr) |
if (kr) |
731 |
return kr; |
return kr; |
732 |
|
|
759 |
kmsg->complex_p = true; |
kmsg->complex_p = true; |
760 |
kmsg->intratask_p = false; |
kmsg->intratask_p = false; |
761 |
|
|
762 |
/* ??? since we do not support OOL memory from kernel yet, |
convert_kernel_to_intermediate (kmsg); |
|
we can just return here since we are done. */ |
|
763 |
return KERN_SUCCESS; |
return KERN_SUCCESS; |
764 |
} |
} |
765 |
|
|
803 |
if (kr) |
if (kr) |
804 |
return kr; |
return kr; |
805 |
|
|
806 |
kr = copyin_body (task, kmsg); |
kr = convert_user_to_intermediate (task, kmsg); |
807 |
if (kr) |
if (kr) |
808 |
return kr; |
return kr; |
809 |
|
|