exception.c 24 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012
  1. /*
  2. * Mach Operating System
  3. * Copyright (c) 1993,1992,1991,1990,1989,1988,1987 Carnegie Mellon University.
  4. * All Rights Reserved.
  5. *
  6. * Permission to use, copy, modify and distribute this software and its
  7. * documentation is hereby granted, provided that both the copyright
  8. * notice and this permission notice appear in all copies of the
  9. * software, derivative works or modified versions, and any portions
  10. * thereof, and that both notices appear in supporting documentation.
  11. *
  12. * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
  13. * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
  14. * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
  15. *
  16. * Carnegie Mellon requests users of this software to return to
  17. *
  18. * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
  19. * School of Computer Science
  20. * Carnegie Mellon University
  21. * Pittsburgh PA 15213-3890
  22. *
  23. * any improvements or extensions that they make and grant Carnegie Mellon
  24. * the rights to redistribute these changes.
  25. */
  26. #include <mach/boolean.h>
  27. #include <mach/kern_return.h>
  28. #include <mach/message.h>
  29. #include <mach/port.h>
  30. #include <mach/mig_errors.h>
  31. #include <machine/locore.h>
  32. #include <ipc/port.h>
  33. #include <ipc/ipc_entry.h>
  34. #include <ipc/ipc_notify.h>
  35. #include <ipc/ipc_object.h>
  36. #include <ipc/ipc_space.h>
  37. #include <ipc/ipc_port.h>
  38. #include <ipc/ipc_pset.h>
  39. #include <ipc/mach_msg.h>
  40. #include <ipc/ipc_machdep.h>
  41. #include <kern/counters.h>
  42. #include <kern/debug.h>
  43. #include <kern/ipc_tt.h>
  44. #include <kern/task.h>
  45. #include <kern/thread.h>
  46. #include <kern/processor.h>
  47. #include <kern/sched.h>
  48. #include <kern/sched_prim.h>
  49. #include <kern/exception.h>
  50. #include <kern/macros.h>
  51. #include <mach/machine/vm_types.h>
  52. #if MACH_KDB
  53. #include <machine/trap.h>
  54. #include <ddb/db_output.h>
  55. boolean_t debug_user_with_kdb = FALSE;
  56. #endif /* MACH_KDB */
  57. #ifdef KEEP_STACKS
  58. /*
  59. * Some obsolete architectures don't support kernel stack discarding
  60. * or the thread_exception_return, thread_syscall_return continuations.
  61. * For these architectures, the NOTREACHED comments below are incorrect.
  62. * The exception function is expected to return.
  63. * So the return statements along the slow paths are important.
  64. */
  65. #endif /* KEEP_STACKS */
  66. /*
  67. * Routine: exception
  68. * Purpose:
  69. * The current thread caught an exception.
  70. * We make an up-call to the thread's exception server.
  71. * Conditions:
  72. * Nothing locked and no resources held.
  73. * Called from an exception context, so
  74. * thread_exception_return and thread_kdb_return
  75. * are possible.
  76. * Returns:
  77. * Doesn't return.
  78. */
  79. void
  80. exception(
  81. integer_t _exception,
  82. integer_t code,
  83. integer_t subcode)
  84. {
  85. ipc_thread_t self = current_thread();
  86. ipc_port_t exc_port;
  87. if (_exception == KERN_SUCCESS)
  88. panic("exception");
  89. /*
  90. * Optimized version of retrieve_thread_exception.
  91. */
  92. ith_lock(self);
  93. assert(self->ith_self != IP_NULL);
  94. exc_port = self->ith_exception;
  95. if (!IP_VALID(exc_port)) {
  96. ith_unlock(self);
  97. exception_try_task(_exception, code, subcode);
  98. /*NOTREACHED*/
  99. }
  100. ip_lock(exc_port);
  101. ith_unlock(self);
  102. if (!ip_active(exc_port)) {
  103. ip_unlock(exc_port);
  104. exception_try_task(_exception, code, subcode);
  105. /*NOTREACHED*/
  106. }
  107. /*
  108. * Make a naked send right for the exception port.
  109. */
  110. ip_reference(exc_port);
  111. exc_port->ip_srights++;
  112. ip_unlock(exc_port);
  113. /*
  114. * If this exception port doesn't work,
  115. * we will want to try the task's exception port.
  116. * Indicate this by saving the exception state.
  117. */
  118. self->ith_exc = _exception;
  119. self->ith_exc_code = code;
  120. self->ith_exc_subcode = subcode;
  121. exception_raise(exc_port,
  122. retrieve_thread_self_fast(self),
  123. retrieve_task_self_fast(self->task),
  124. _exception, code, subcode);
  125. /*NOTREACHED*/
  126. }
  127. /*
  128. * Routine: exception_try_task
  129. * Purpose:
  130. * The current thread caught an exception.
  131. * We make an up-call to the task's exception server.
  132. * Conditions:
  133. * Nothing locked and no resources held.
  134. * Called from an exception context, so
  135. * thread_exception_return and thread_kdb_return
  136. * are possible.
  137. * Returns:
  138. * Doesn't return.
  139. */
  140. void
  141. exception_try_task(
  142. integer_t _exception,
  143. integer_t code,
  144. integer_t subcode)
  145. {
  146. ipc_thread_t self = current_thread();
  147. task_t task = self->task;
  148. ipc_port_t exc_port;
  149. /*
  150. * Optimized version of retrieve_task_exception.
  151. */
  152. itk_lock(task);
  153. assert(task->itk_self != IP_NULL);
  154. exc_port = task->itk_exception;
  155. if (!IP_VALID(exc_port)) {
  156. itk_unlock(task);
  157. exception_no_server();
  158. /*NOTREACHED*/
  159. }
  160. ip_lock(exc_port);
  161. itk_unlock(task);
  162. if (!ip_active(exc_port)) {
  163. ip_unlock(exc_port);
  164. exception_no_server();
  165. /*NOTREACHED*/
  166. }
  167. /*
  168. * Make a naked send right for the exception port.
  169. */
  170. ip_reference(exc_port);
  171. exc_port->ip_srights++;
  172. ip_unlock(exc_port);
  173. /*
  174. * This is the thread's last chance.
  175. * Clear the saved exception state.
  176. */
  177. self->ith_exc = KERN_SUCCESS;
  178. exception_raise(exc_port,
  179. retrieve_thread_self_fast(self),
  180. retrieve_task_self_fast(task),
  181. _exception, code, subcode);
  182. /*NOTREACHED*/
  183. }
  184. /*
  185. * Routine: exception_no_server
  186. * Purpose:
  187. * The current thread took an exception,
  188. * and no exception server took responsibility
  189. * for the exception. So good bye, charlie.
  190. * Conditions:
  191. * Nothing locked and no resources held.
  192. * Called from an exception context, so
  193. * thread_kdb_return is possible.
  194. * Returns:
  195. * Doesn't return.
  196. */
  197. void
  198. exception_no_server(void)
  199. {
  200. ipc_thread_t self = current_thread();
  201. /*
  202. * If this thread is being terminated, cooperate.
  203. */
  204. while (thread_should_halt(self))
  205. thread_halt_self(thread_exception_return);
  206. #if 0
  207. if (thread_suspend (self) == KERN_SUCCESS)
  208. thread_exception_return ();
  209. #endif
  210. #if MACH_KDB
  211. if (debug_user_with_kdb) {
  212. /*
  213. * Debug the exception with kdb.
  214. * If kdb handles the exception,
  215. * then thread_kdb_return won't return.
  216. */
  217. db_printf("No exception server, calling kdb...\n");
  218. thread_kdb_return();
  219. }
  220. #endif /* MACH_KDB */
  221. /*
  222. * All else failed; terminate task.
  223. */
  224. (void) task_terminate(self->task);
  225. thread_halt_self(thread_exception_return);
  226. panic("terminating the task didn't kill us");
  227. /*NOTREACHED*/
  228. }
  229. #define MACH_EXCEPTION_ID 2400 /* from mach/exc.defs */
  230. #define MACH_EXCEPTION_REPLY_ID (MACH_EXCEPTION_ID + 100)
  231. struct mach_exception {
  232. mach_msg_header_t Head;
  233. mach_msg_type_t threadType;
  234. mach_port_t thread;
  235. mach_msg_type_t taskType;
  236. mach_port_t task;
  237. mach_msg_type_t exceptionType;
  238. integer_t exception;
  239. mach_msg_type_t codeType;
  240. integer_t code;
  241. mach_msg_type_t subcodeType;
  242. integer_t subcode;
  243. };
  244. #define INTEGER_T_SIZE_IN_BITS (8 * sizeof(integer_t))
  245. #define INTEGER_T_TYPE MACH_MSG_TYPE_INTEGER_T
  246. /* in mach/machine/vm_types.h */
  247. mach_msg_type_t exc_port_proto = {
  248. /* msgt_name = */ MACH_MSG_TYPE_PORT_SEND,
  249. /* msgt_size = */ PORT_T_SIZE_IN_BITS,
  250. /* msgt_number = */ 1,
  251. /* msgt_inline = */ TRUE,
  252. /* msgt_longform = */ FALSE,
  253. /* msgt_deallocate = */ FALSE,
  254. /* msgt_unused = */ 0
  255. };
  256. mach_msg_type_t exc_code_proto = {
  257. /* msgt_name = */ INTEGER_T_TYPE,
  258. /* msgt_size = */ INTEGER_T_SIZE_IN_BITS,
  259. /* msgt_number = */ 1,
  260. /* msgt_inline = */ TRUE,
  261. /* msgt_longform = */ FALSE,
  262. /* msgt_deallocate = */ FALSE,
  263. /* msgt_unused = */ 0
  264. };
  265. /*
  266. * Routine: exception_raise
  267. * Purpose:
  268. * Make an exception_raise up-call to an exception server.
  269. *
  270. * dest_port must be a valid naked send right.
  271. * thread_port and task_port are naked send rights.
  272. * All three are always consumed.
  273. *
  274. * self->ith_exc, self->ith_exc_code, self->ith_exc_subcode
  275. * must be appropriately initialized.
  276. * Conditions:
  277. * Nothing locked. We are being called in an exception context,
  278. * so thread_exception_return may be called.
  279. * Returns:
  280. * Doesn't return.
  281. */
  282. int exception_raise_misses = 0;
  283. void
  284. exception_raise(
  285. ipc_port_t dest_port,
  286. ipc_port_t thread_port,
  287. ipc_port_t task_port,
  288. integer_t _exception,
  289. integer_t code,
  290. integer_t subcode)
  291. {
  292. ipc_thread_t self = current_thread();
  293. ipc_thread_t receiver;
  294. ipc_port_t reply_port;
  295. ipc_mqueue_t dest_mqueue;
  296. ipc_mqueue_t reply_mqueue;
  297. ipc_kmsg_t kmsg;
  298. mach_msg_return_t mr;
  299. assert(IP_VALID(dest_port));
  300. /*
  301. * We will eventually need a message buffer.
  302. * Grab the buffer now, while nothing is locked.
  303. * This buffer will get handed to the exception server,
  304. * and it will give the buffer back with its reply.
  305. */
  306. kmsg = ikm_cache();
  307. if (kmsg != IKM_NULL) {
  308. ikm_cache() = IKM_NULL;
  309. ikm_check_initialized(kmsg, IKM_SAVED_KMSG_SIZE);
  310. } else {
  311. kmsg = ikm_alloc(IKM_SAVED_MSG_SIZE);
  312. if (kmsg == IKM_NULL)
  313. panic("exception_raise");
  314. ikm_init(kmsg, IKM_SAVED_MSG_SIZE);
  315. }
  316. /*
  317. * We need a reply port for the RPC.
  318. * Check first for a cached port.
  319. */
  320. ith_lock(self);
  321. assert(self->ith_self != IP_NULL);
  322. reply_port = self->ith_rpc_reply;
  323. if (reply_port == IP_NULL) {
  324. ith_unlock(self);
  325. reply_port = ipc_port_alloc_reply();
  326. ith_lock(self);
  327. if ((reply_port == IP_NULL) ||
  328. (self->ith_rpc_reply != IP_NULL))
  329. panic("exception_raise");
  330. self->ith_rpc_reply = reply_port;
  331. }
  332. ip_lock(reply_port);
  333. assert(ip_active(reply_port));
  334. ith_unlock(self);
  335. /*
  336. * Make a naked send-once right for the reply port,
  337. * to hand to the exception server.
  338. * Make an extra reference for the reply port,
  339. * to receive on. This protects us against
  340. * mach_msg_abort_rpc.
  341. */
  342. reply_port->ip_sorights++;
  343. ip_reference(reply_port);
  344. ip_reference(reply_port);
  345. self->ith_port = reply_port;
  346. reply_mqueue = &reply_port->ip_messages;
  347. imq_lock(reply_mqueue);
  348. assert(ipc_kmsg_queue_empty(&reply_mqueue->imq_messages));
  349. ip_unlock(reply_port);
  350. /*
  351. * Make sure we can queue to the destination port.
  352. */
  353. if (!ip_lock_try(dest_port)) {
  354. imq_unlock(reply_mqueue);
  355. goto slow_exception_raise;
  356. }
  357. if (!ip_active(dest_port) ||
  358. (dest_port->ip_receiver == ipc_space_kernel)) {
  359. imq_unlock(reply_mqueue);
  360. ip_unlock(dest_port);
  361. goto slow_exception_raise;
  362. }
  363. /*
  364. * Find the destination message queue.
  365. */
  366. {
  367. ipc_pset_t dest_pset;
  368. dest_pset = dest_port->ip_pset;
  369. if (dest_pset == IPS_NULL)
  370. dest_mqueue = &dest_port->ip_messages;
  371. else
  372. dest_mqueue = &dest_pset->ips_messages;
  373. }
  374. if (!imq_lock_try(dest_mqueue)) {
  375. imq_unlock(reply_mqueue);
  376. ip_unlock(dest_port);
  377. goto slow_exception_raise;
  378. }
  379. /*
  380. * Safe to unlock dest_port, because we hold
  381. * dest_mqueue locked. We never bother changing
  382. * dest_port->ip_msgcount.
  383. */
  384. ip_unlock(dest_port);
  385. receiver = ipc_thread_queue_first(&dest_mqueue->imq_threads);
  386. if ((receiver == ITH_NULL) ||
  387. !((receiver->swap_func == (void (*)()) mach_msg_continue) ||
  388. ((receiver->swap_func ==
  389. (void (*)()) mach_msg_receive_continue) &&
  390. (sizeof(struct mach_exception) <= receiver->ith_msize) &&
  391. ((receiver->ith_option & MACH_RCV_NOTIFY) == 0))) ||
  392. !thread_handoff(self, exception_raise_continue, receiver)) {
  393. imq_unlock(reply_mqueue);
  394. imq_unlock(dest_mqueue);
  395. goto slow_exception_raise;
  396. }
  397. counter(c_exception_raise_block++);
  398. assert(current_thread() == receiver);
  399. /*
  400. * We need to finish preparing self for its
  401. * time asleep in reply_mqueue. self is left
  402. * holding the extra ref for reply_port.
  403. */
  404. ipc_thread_enqueue_macro(&reply_mqueue->imq_threads, self);
  405. self->ith_state = MACH_RCV_IN_PROGRESS;
  406. self->ith_msize = MACH_MSG_SIZE_MAX;
  407. imq_unlock(reply_mqueue);
  408. /*
  409. * Finish extracting receiver from dest_mqueue.
  410. */
  411. ipc_thread_rmqueue_first_macro(
  412. &dest_mqueue->imq_threads, receiver);
  413. imq_unlock(dest_mqueue);
  414. /*
  415. * Release the receiver's reference for his object.
  416. */
  417. {
  418. ipc_object_t object = receiver->ith_object;
  419. io_lock(object);
  420. io_release(object);
  421. io_check_unlock(object);
  422. }
  423. {
  424. struct mach_exception *exc =
  425. (struct mach_exception *) &kmsg->ikm_header;
  426. ipc_space_t space = receiver->task->itk_space;
  427. /*
  428. * We are running as the receiver now. We hold
  429. * the following resources, which must be consumed:
  430. * kmsg, send-once right for reply_port
  431. * send rights for dest_port, thread_port, task_port
  432. * Synthesize a kmsg for copyout to the receiver.
  433. */
  434. exc->Head.msgh_bits = (MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE,
  435. MACH_MSG_TYPE_PORT_SEND) |
  436. MACH_MSGH_BITS_COMPLEX);
  437. exc->Head.msgh_size = sizeof *exc;
  438. /* exc->Head.msgh_remote_port later */
  439. /* exc->Head.msgh_local_port later */
  440. exc->Head.msgh_seqno = 0;
  441. exc->Head.msgh_id = MACH_EXCEPTION_ID;
  442. exc->threadType = exc_port_proto;
  443. /* exc->thread later */
  444. exc->taskType = exc_port_proto;
  445. /* exc->task later */
  446. exc->exceptionType = exc_code_proto;
  447. exc->exception = _exception;
  448. exc->codeType = exc_code_proto;
  449. exc->code = code;
  450. exc->subcodeType = exc_code_proto;
  451. exc->subcode = subcode;
  452. /*
  453. * Check that the receiver can handle the message.
  454. */
  455. if (receiver->ith_rcv_size < sizeof(struct mach_exception)) {
  456. /*
  457. * ipc_kmsg_destroy is a handy way to consume
  458. * the resources we hold, but it requires setup.
  459. */
  460. exc->Head.msgh_bits =
  461. (MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND,
  462. MACH_MSG_TYPE_PORT_SEND_ONCE) |
  463. MACH_MSGH_BITS_COMPLEX);
  464. exc->Head.msgh_remote_port = (mach_port_t) dest_port;
  465. exc->Head.msgh_local_port = (mach_port_t) reply_port;
  466. exc->thread = (mach_port_t) thread_port;
  467. exc->task = (mach_port_t) task_port;
  468. ipc_kmsg_destroy(kmsg);
  469. thread_syscall_return(MACH_RCV_TOO_LARGE);
  470. /*NOTREACHED*/
  471. }
  472. is_write_lock(space);
  473. assert(space->is_active);
  474. /*
  475. * To do an atomic copyout, need simultaneous
  476. * locks on both ports and the space.
  477. */
  478. ip_lock(dest_port);
  479. if (!ip_active(dest_port) ||
  480. !ip_lock_try(reply_port)) {
  481. abort_copyout:
  482. ip_unlock(dest_port);
  483. is_write_unlock(space);
  484. /*
  485. * Oh well, we have to do the header the slow way.
  486. * First make it look like it's in-transit.
  487. */
  488. exc->Head.msgh_bits =
  489. (MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND,
  490. MACH_MSG_TYPE_PORT_SEND_ONCE) |
  491. MACH_MSGH_BITS_COMPLEX);
  492. exc->Head.msgh_remote_port = (mach_port_t) dest_port;
  493. exc->Head.msgh_local_port = (mach_port_t) reply_port;
  494. mr = ipc_kmsg_copyout_header(&exc->Head, space,
  495. MACH_PORT_NULL);
  496. if (mr == MACH_MSG_SUCCESS)
  497. goto copyout_body;
  498. /*
  499. * Ack! Prepare for ipc_kmsg_copyout_dest.
  500. * It will consume thread_port and task_port.
  501. */
  502. exc->thread = (mach_port_t) thread_port;
  503. exc->task = (mach_port_t) task_port;
  504. ipc_kmsg_copyout_dest(kmsg, space);
  505. (void) ipc_kmsg_put(receiver->ith_msg, kmsg,
  506. sizeof(mach_msg_header_t));
  507. thread_syscall_return(mr);
  508. /*NOTREACHED*/
  509. }
  510. if (!ip_active(reply_port)) {
  511. ip_unlock(reply_port);
  512. goto abort_copyout;
  513. }
  514. assert(reply_port->ip_sorights > 0);
  515. ip_unlock(reply_port);
  516. {
  517. kern_return_t kr;
  518. ipc_entry_t entry;
  519. kr = ipc_entry_get (space, &exc->Head.msgh_remote_port, &entry);
  520. if (kr)
  521. goto abort_copyout;
  522. {
  523. mach_port_gen_t gen;
  524. assert((entry->ie_bits &~ IE_BITS_GEN_MASK) == 0);
  525. gen = entry->ie_bits + IE_BITS_GEN_ONE;
  526. /* optimized ipc_right_copyout */
  527. entry->ie_bits = gen | (MACH_PORT_TYPE_SEND_ONCE | 1);
  528. }
  529. entry->ie_object = (ipc_object_t) reply_port;
  530. is_write_unlock(space);
  531. }
  532. /* optimized ipc_object_copyout_dest */
  533. assert(dest_port->ip_srights > 0);
  534. ip_release(dest_port);
  535. exc->Head.msgh_local_port =
  536. ((dest_port->ip_receiver == space) ?
  537. dest_port->ip_receiver_name : MACH_PORT_NULL);
  538. if ((--dest_port->ip_srights == 0) &&
  539. (dest_port->ip_nsrequest != IP_NULL)) {
  540. ipc_port_t nsrequest;
  541. mach_port_mscount_t mscount;
  542. /* a rather rare case */
  543. nsrequest = dest_port->ip_nsrequest;
  544. mscount = dest_port->ip_mscount;
  545. dest_port->ip_nsrequest = IP_NULL;
  546. ip_unlock(dest_port);
  547. ipc_notify_no_senders(nsrequest, mscount);
  548. } else
  549. ip_unlock(dest_port);
  550. copyout_body:
  551. /*
  552. * Optimized version of ipc_kmsg_copyout_body,
  553. * to handle the two ports in the body.
  554. */
  555. mr = (ipc_kmsg_copyout_object(space, (ipc_object_t) thread_port,
  556. MACH_MSG_TYPE_PORT_SEND, &exc->thread) |
  557. ipc_kmsg_copyout_object(space, (ipc_object_t) task_port,
  558. MACH_MSG_TYPE_PORT_SEND, &exc->task));
  559. if (mr != MACH_MSG_SUCCESS) {
  560. (void) ipc_kmsg_put(receiver->ith_msg, kmsg,
  561. kmsg->ikm_header.msgh_size);
  562. thread_syscall_return(mr | MACH_RCV_BODY_ERROR);
  563. /*NOTREACHED*/
  564. }
  565. }
  566. /*
  567. * Optimized version of ipc_kmsg_put.
  568. * We must check ikm_cache after copyoutmsg.
  569. */
  570. ikm_check_initialized(kmsg, kmsg->ikm_size);
  571. assert(kmsg->ikm_size == IKM_SAVED_KMSG_SIZE);
  572. if (copyoutmsg(&kmsg->ikm_header, receiver->ith_msg,
  573. sizeof(struct mach_exception)) ||
  574. (ikm_cache() != IKM_NULL)) {
  575. mr = ipc_kmsg_put(receiver->ith_msg, kmsg,
  576. kmsg->ikm_header.msgh_size);
  577. thread_syscall_return(mr);
  578. /*NOTREACHED*/
  579. }
  580. ikm_cache() = kmsg;
  581. thread_syscall_return(MACH_MSG_SUCCESS);
  582. /*NOTREACHED*/
  583. #ifndef __GNUC__
  584. return; /* help for the compiler */
  585. #endif
  586. slow_exception_raise: {
  587. struct mach_exception *exc =
  588. (struct mach_exception *) &kmsg->ikm_header;
  589. ipc_kmsg_t reply_kmsg;
  590. mach_port_seqno_t reply_seqno;
  591. exception_raise_misses++;
  592. /*
  593. * We hold the following resources, which must be consumed:
  594. * kmsg, send-once right and ref for reply_port
  595. * send rights for dest_port, thread_port, task_port
  596. * Synthesize a kmsg to send.
  597. */
  598. exc->Head.msgh_bits = (MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND,
  599. MACH_MSG_TYPE_PORT_SEND_ONCE) |
  600. MACH_MSGH_BITS_COMPLEX);
  601. exc->Head.msgh_size = sizeof *exc;
  602. exc->Head.msgh_remote_port = (mach_port_t) dest_port;
  603. exc->Head.msgh_local_port = (mach_port_t) reply_port;
  604. exc->Head.msgh_seqno = 0;
  605. exc->Head.msgh_id = MACH_EXCEPTION_ID;
  606. exc->threadType = exc_port_proto;
  607. exc->thread = (mach_port_t) thread_port;
  608. exc->taskType = exc_port_proto;
  609. exc->task = (mach_port_t) task_port;
  610. exc->exceptionType = exc_code_proto;
  611. exc->exception = _exception;
  612. exc->codeType = exc_code_proto;
  613. exc->code = code;
  614. exc->subcodeType = exc_code_proto;
  615. exc->subcode = subcode;
  616. ipc_mqueue_send_always(kmsg);
  617. /*
  618. * We are left with a ref for reply_port,
  619. * which we use to receive the reply message.
  620. */
  621. ip_lock(reply_port);
  622. if (!ip_active(reply_port)) {
  623. ip_unlock(reply_port);
  624. exception_raise_continue_slow(MACH_RCV_PORT_DIED, IKM_NULL, /*dummy*/0);
  625. /*NOTREACHED*/
  626. }
  627. imq_lock(reply_mqueue);
  628. ip_unlock(reply_port);
  629. mr = ipc_mqueue_receive(reply_mqueue, MACH_MSG_OPTION_NONE,
  630. MACH_MSG_SIZE_MAX,
  631. MACH_MSG_TIMEOUT_NONE,
  632. FALSE, exception_raise_continue,
  633. &reply_kmsg, &reply_seqno);
  634. /* reply_mqueue is unlocked */
  635. exception_raise_continue_slow(mr, reply_kmsg, reply_seqno);
  636. /*NOTREACHED*/
  637. }
  638. }
  639. /* Macro used by MIG to cleanly check the type. */
  640. #define BAD_TYPECHECK(type, check) unlikely (({\
  641. union { mach_msg_type_t t; uint32_t w; } _t, _c;\
  642. _t.t = *(type); _c.t = *(check);_t.w != _c.w; }))
  643. /* Type descriptor for the return code. */
  644. mach_msg_type_t exc_RetCode_proto = {
  645. /* msgt_name = */ MACH_MSG_TYPE_INTEGER_32,
  646. /* msgt_size = */ 32,
  647. /* msgt_number = */ 1,
  648. /* msgt_inline = */ TRUE,
  649. /* msgt_longform = */ FALSE,
  650. /* msgt_deallocate = */ FALSE,
  651. /* msgt_unused = */ 0
  652. };
  653. /*
  654. * Routine: exception_parse_reply
  655. * Purpose:
  656. * Parse and consume an exception reply message.
  657. * Conditions:
  658. * The destination port right has already been consumed.
  659. * The message buffer and anything else in it is consumed.
  660. * Returns:
  661. * The reply return code.
  662. */
  663. kern_return_t
  664. exception_parse_reply(ipc_kmsg_t kmsg)
  665. {
  666. mig_reply_header_t *msg =
  667. (mig_reply_header_t *) &kmsg->ikm_header;
  668. kern_return_t kr;
  669. if ((msg->Head.msgh_bits !=
  670. MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, 0)) ||
  671. (msg->Head.msgh_size != sizeof *msg) ||
  672. (msg->Head.msgh_id != MACH_EXCEPTION_REPLY_ID) ||
  673. (BAD_TYPECHECK(&msg->RetCodeType, &exc_RetCode_proto))) {
  674. /*
  675. * Bozo user sent us a misformatted reply.
  676. */
  677. kmsg->ikm_header.msgh_remote_port = MACH_PORT_NULL;
  678. ipc_kmsg_destroy(kmsg);
  679. return MIG_REPLY_MISMATCH;
  680. }
  681. kr = msg->RetCode;
  682. if ((kmsg->ikm_size == IKM_SAVED_KMSG_SIZE) &&
  683. (ikm_cache() == IKM_NULL))
  684. ikm_cache() = kmsg;
  685. else
  686. ikm_free(kmsg);
  687. return kr;
  688. }
  689. /*
  690. * Routine: exception_raise_continue
  691. * Purpose:
  692. * Continue after blocking for an exception.
  693. * Conditions:
  694. * Nothing locked. We are running on a new kernel stack,
  695. * with the exception state saved in the thread. From here
  696. * control goes back to user space.
  697. * Returns:
  698. * Doesn't return.
  699. */
  700. void
  701. exception_raise_continue(void)
  702. {
  703. ipc_thread_t self = current_thread();
  704. ipc_port_t reply_port = self->ith_port;
  705. ipc_mqueue_t reply_mqueue = &reply_port->ip_messages;
  706. ipc_kmsg_t kmsg;
  707. mach_port_seqno_t seqno;
  708. mach_msg_return_t mr;
  709. mr = ipc_mqueue_receive(reply_mqueue, MACH_MSG_OPTION_NONE,
  710. MACH_MSG_SIZE_MAX,
  711. MACH_MSG_TIMEOUT_NONE,
  712. TRUE, exception_raise_continue,
  713. &kmsg, &seqno);
  714. /* reply_mqueue is unlocked */
  715. exception_raise_continue_slow(mr, kmsg, seqno);
  716. /*NOTREACHED*/
  717. }
  718. /*
  719. * Routine: thread_release_and_exception_return
  720. * Purpose:
  721. * Continue after thread was halted.
  722. * Conditions:
  723. * Nothing locked. We are running on a new kernel stack and
  724. * control goes back to thread_exception_return.
  725. * Returns:
  726. * Doesn't return.
  727. */
  728. static void
  729. thread_release_and_exception_return(void)
  730. {
  731. ipc_thread_t self = current_thread();
  732. /* reply port must be released */
  733. ipc_port_release(self->ith_port);
  734. thread_exception_return();
  735. /*NOTREACHED*/
  736. }
  737. /*
  738. * Routine: exception_raise_continue_slow
  739. * Purpose:
  740. * Continue after finishing an ipc_mqueue_receive
  741. * for an exception reply message.
  742. * Conditions:
  743. * Nothing locked. We hold a ref for reply_port.
  744. * Returns:
  745. * Doesn't return.
  746. */
  747. void
  748. exception_raise_continue_slow(
  749. mach_msg_return_t mr,
  750. ipc_kmsg_t kmsg,
  751. mach_port_seqno_t seqno)
  752. {
  753. ipc_thread_t self = current_thread();
  754. ipc_port_t reply_port = self->ith_port;
  755. ipc_mqueue_t reply_mqueue = &reply_port->ip_messages;
  756. while (mr == MACH_RCV_INTERRUPTED) {
  757. /*
  758. * Somebody is trying to force this thread
  759. * to a clean point. We must cooperate
  760. * and then resume the receive.
  761. */
  762. while (thread_should_halt(self)) {
  763. /* if thread is about to terminate, release the port */
  764. if (self->ast & AST_TERMINATE)
  765. ipc_port_release(reply_port);
  766. /*
  767. * Use the continuation to release the port in
  768. * case the thread is about to halt.
  769. */
  770. thread_halt_self(thread_release_and_exception_return);
  771. }
  772. ip_lock(reply_port);
  773. if (!ip_active(reply_port)) {
  774. ip_unlock(reply_port);
  775. mr = MACH_RCV_PORT_DIED;
  776. break;
  777. }
  778. imq_lock(reply_mqueue);
  779. ip_unlock(reply_port);
  780. mr = ipc_mqueue_receive(reply_mqueue, MACH_MSG_OPTION_NONE,
  781. MACH_MSG_SIZE_MAX,
  782. MACH_MSG_TIMEOUT_NONE,
  783. FALSE, exception_raise_continue,
  784. &kmsg, &seqno);
  785. /* reply_mqueue is unlocked */
  786. }
  787. ipc_port_release(reply_port);
  788. assert((mr == MACH_MSG_SUCCESS) ||
  789. (mr == MACH_RCV_PORT_DIED));
  790. if (mr == MACH_MSG_SUCCESS) {
  791. /*
  792. * Consume the reply message.
  793. */
  794. ipc_port_release_sonce(reply_port);
  795. mr = exception_parse_reply(kmsg);
  796. }
  797. if ((mr == KERN_SUCCESS) ||
  798. (mr == MACH_RCV_PORT_DIED)) {
  799. thread_exception_return();
  800. /*NOTREACHED*/
  801. }
  802. if (self->ith_exc != KERN_SUCCESS) {
  803. exception_try_task(self->ith_exc,
  804. self->ith_exc_code,
  805. self->ith_exc_subcode);
  806. /*NOTREACHED*/
  807. }
  808. exception_no_server();
  809. /*NOTREACHED*/
  810. }
  811. /*
  812. * Routine: exception_raise_continue_fast
  813. * Purpose:
  814. * Special-purpose fast continuation for exceptions.
  815. * Conditions:
  816. * reply_port is locked and alive.
  817. * kmsg is our reply message.
  818. * Returns:
  819. * Doesn't return.
  820. */
  821. void
  822. exception_raise_continue_fast(
  823. ipc_port_t reply_port,
  824. ipc_kmsg_t kmsg)
  825. {
  826. ipc_thread_t self = current_thread();
  827. kern_return_t kr;
  828. assert(ip_active(reply_port));
  829. assert(reply_port == self->ith_port);
  830. assert(reply_port == (ipc_port_t) kmsg->ikm_header.msgh_remote_port);
  831. assert(MACH_MSGH_BITS_REMOTE(kmsg->ikm_header.msgh_bits) ==
  832. MACH_MSG_TYPE_PORT_SEND_ONCE);
  833. /*
  834. * Release the send-once right (from the message header)
  835. * and the saved reference (from self->ith_port).
  836. */
  837. reply_port->ip_sorights--;
  838. ip_release(reply_port);
  839. ip_release(reply_port);
  840. ip_unlock(reply_port);
  841. /*
  842. * Consume the reply message.
  843. */
  844. kr = exception_parse_reply(kmsg);
  845. if (kr == KERN_SUCCESS) {
  846. thread_exception_return();
  847. /*NOTREACHED*/
  848. }
  849. if (self->ith_exc != KERN_SUCCESS) {
  850. exception_try_task(self->ith_exc,
  851. self->ith_exc_code,
  852. self->ith_exc_subcode);
  853. /*NOTREACHED*/
  854. }
  855. exception_no_server();
  856. /*NOTREACHED*/
  857. }