123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901 |
- /*
- * Mach Operating System
- * Copyright (c) 1991,1990,1989 Carnegie Mellon University.
- * Copyright (c) 1993,1994 The University of Utah and
- * the Computer Systems Laboratory (CSL).
- * All rights reserved.
- *
- * Permission to use, copy, modify and distribute this software and its
- * documentation is hereby granted, provided that both the copyright
- * notice and this permission notice appear in all copies of the
- * software, derivative works or modified versions, and any portions
- * thereof, and that both notices appear in supporting documentation.
- *
- * CARNEGIE MELLON, THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF
- * THIS SOFTWARE IN ITS "AS IS" CONDITION, AND DISCLAIM ANY LIABILITY
- * OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF
- * THIS SOFTWARE.
- *
- * Carnegie Mellon requests users of this software to return to
- *
- * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
- * School of Computer Science
- * Carnegie Mellon University
- * Pittsburgh PA 15213-3890
- *
- * any improvements or extensions that they make and grant Carnegie Mellon
- * the rights to redistribute these changes.
- */
- /*
- * File: ipc/ipc_kmsg.c
- * Author: Rich Draves
- * Date: 1989
- *
- * Operations on kernel messages.
- */
- #include <glue/gnulinux.h>
- #include <kern/printf.h>
- #include <string.h>
- #include <mach/boolean.h>
- #include <mach/kern_return.h>
- #include <mach/message.h>
- #include <mach/port.h>
- #include <kern/assert.h>
- #include <kern/kalloc.h>
- #include <vm/vm_map.h>
- #include <vm/vm_object.h>
- #include <vm/vm_kern.h>
- #include <vm/vm_user.h>
- #include <ipc/port.h>
- #include <ipc/ipc_entry.h>
- #include <ipc/ipc_kmsg.h>
- #include <ipc/ipc_thread.h>
- #include <ipc/ipc_marequest.h>
- #include <ipc/ipc_notify.h>
- #include <ipc/ipc_object.h>
- #include <ipc/ipc_space.h>
- #include <ipc/ipc_port.h>
- #include <ipc/ipc_right.h>
- #include <ipc/ipc_machdep.h>
- #include <glue/locore.h>
- int ipc_reverse_lookup(void*,void*);
- void net_kmsg_put(void* mem){}
- #if MACH_KDB
- #include <ddb/db_output.h>
- #include <ipc/ipc_print.h>
- #endif
- #define is_misaligned(x) ( ((vm_offset_t)(x)) & (sizeof(vm_offset_t)-1) )
- #define ptr_align(x) \
- ( ( ((vm_offset_t)(x)) + (sizeof(vm_offset_t)-1) ) & ~(sizeof(vm_offset_t)-1) )
- ipc_kmsg_t ipc_kmsg_cache[NCPUS];
- /*
- * Routine: ipc_kmsg_enqueue
- * Purpose:
- * Enqueue a kmsg.
- */
- void
- ipc_kmsg_enqueue(
- ipc_kmsg_queue_t queue,
- ipc_kmsg_t kmsg)
- {
- ipc_kmsg_enqueue_macro(queue, kmsg);
- }
- /*
- * Routine: ipc_kmsg_dequeue
- * Purpose:
- * Dequeue and return a kmsg.
- */
- ipc_kmsg_t
- ipc_kmsg_dequeue(
- ipc_kmsg_queue_t queue)
- {
- ipc_kmsg_t first;
- first = ipc_kmsg_queue_first(queue);
- if (first != IKM_NULL)
- ipc_kmsg_rmqueue_first_macro(queue, first);
- return first;
- }
- /*
- * Routine: ipc_kmsg_rmqueue
- * Purpose:
- * Pull a kmsg out of a queue.
- */
- void
- ipc_kmsg_rmqueue(
- ipc_kmsg_queue_t queue,
- ipc_kmsg_t kmsg)
- {
- ipc_kmsg_t next, prev;
- assert(queue->ikmq_base != IKM_NULL);
- next = kmsg->ikm_next;
- prev = kmsg->ikm_prev;
- if (next == kmsg) {
- assert(prev == kmsg);
- assert(queue->ikmq_base == kmsg);
- queue->ikmq_base = IKM_NULL;
- } else {
- if (queue->ikmq_base == kmsg)
- queue->ikmq_base = next;
- next->ikm_prev = prev;
- prev->ikm_next = next;
- }
- ikm_mark_bogus (kmsg);
- }
- /*
- * Routine: ipc_kmsg_queue_next
- * Purpose:
- * Return the kmsg following the given kmsg.
- * (Or IKM_NULL if it is the last one in the queue.)
- */
- ipc_kmsg_t
- ipc_kmsg_queue_next(
- ipc_kmsg_queue_t queue,
- ipc_kmsg_t kmsg)
- {
- ipc_kmsg_t next;
- assert(queue->ikmq_base != IKM_NULL);
- next = kmsg->ikm_next;
- if (queue->ikmq_base == next)
- next = IKM_NULL;
- return next;
- }
- /*
- * Routine: ipc_kmsg_destroy
- * Purpose:
- * Destroys a kernel message. Releases all rights,
- * references, and memory held by the message.
- * Frees the message.
- * Conditions:
- * No locks held.
- */
- void
- ipc_kmsg_destroy(
- ipc_kmsg_t kmsg)
- {
- ipc_kmsg_queue_t queue;
- boolean_t empty;
- /*
- * ipc_kmsg_clean can cause more messages to be destroyed.
- * Curtail recursion by queueing messages. If a message
- * is already queued, then this is a recursive call.
- */
- queue = ¤t_thread()->ith_messages;
- empty = ipc_kmsg_queue_empty(queue);
- ipc_kmsg_enqueue(queue, kmsg);
- if (empty) {
- /* must leave kmsg in queue while cleaning it */
- while ((kmsg = ipc_kmsg_queue_first(queue)) != IKM_NULL) {
- ipc_kmsg_clean(kmsg);
- ipc_kmsg_rmqueue(queue, kmsg);
- ikm_free(kmsg);
- }
- }
- }
- /*
- * Routine: ipc_kmsg_clean_body
- * Purpose:
- * Cleans the body of a kernel message.
- * Releases all rights, references, and memory.
- *
- * The last type/data pair might stretch past eaddr.
- * (See the usage in ipc_kmsg_copyout.)
- * Conditions:
- * No locks held.
- */
- void
- ipc_kmsg_clean_body(
- vm_offset_t saddr,
- vm_offset_t eaddr)
- {
- while (saddr < eaddr) {
- mach_msg_type_long_t *type;
- mach_msg_type_name_t name;
- mach_msg_type_size_t size;
- mach_msg_type_number_t number;
- boolean_t is_inline, is_port;
- vm_size_t length;
- type = (mach_msg_type_long_t *) saddr;
- is_inline = ((mach_msg_type_t*)type)->msgt_inline;
- if (((mach_msg_type_t*)type)->msgt_longform) {
- /* This must be aligned */
- if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
- (is_misaligned(type))) {
- saddr = ptr_align(saddr);
- continue;
- }
- name = type->msgtl_name;
- size = type->msgtl_size;
- number = type->msgtl_number;
- saddr += sizeof(mach_msg_type_long_t);
- } else {
- name = ((mach_msg_type_t*)type)->msgt_name;
- size = ((mach_msg_type_t*)type)->msgt_size;
- number = ((mach_msg_type_t*)type)->msgt_number;
- saddr += sizeof(mach_msg_type_t);
- }
- /* padding (ptrs and ports) ? */
- if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
- ((size >> 3) == sizeof(natural_t)))
- saddr = ptr_align(saddr);
- /* calculate length of data in bytes, rounding up */
- length = ((number * size) + 7) >> 3;
- is_port = MACH_MSG_TYPE_PORT_ANY(name);
- if (is_port) {
- ipc_object_t *objects;
- mach_msg_type_number_t i;
- if (is_inline) {
- objects = (ipc_object_t *) saddr;
- /* sanity check */
- while (eaddr < (vm_offset_t)&objects[number]) number--;
- } else {
- objects = (ipc_object_t *)
- * (vm_offset_t *) saddr;
- }
- /* destroy port rights carried in the message */
- for (i = 0; i < number; i++) {
- ipc_object_t object = objects[i];
- if (!IO_VALID(object))
- continue;
- ipc_object_destroy(object, name);
- }
- }
- if (is_inline) {
- /* inline data sizes round up to int boundaries */
- saddr += (length + 3) &~ 3;
- } else {
- vm_offset_t data = * (vm_offset_t *) saddr;
- /* destroy memory carried in the message */
- if (length == 0)
- assert(data == 0);
- else if (is_port)
- kfree(data, length);
- else
- vm_map_copy_discard((vm_map_copy_t) data);
- saddr += sizeof(vm_offset_t);
- }
- }
- }
- /*
- * Routine: ipc_kmsg_clean
- * Purpose:
- * Cleans a kernel message. Releases all rights,
- * references, and memory held by the message.
- * Conditions:
- * No locks held.
- */
- void
- ipc_kmsg_clean(ipc_kmsg_t kmsg)
- {
- ipc_marequest_t marequest;
- ipc_object_t object;
- mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits;
- marequest = kmsg->ikm_marequest;
- if (marequest != IMAR_NULL)
- ipc_marequest_destroy(marequest);
- object = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
- if (IO_VALID(object))
- ipc_object_destroy(object, MACH_MSGH_BITS_REMOTE(mbits));
- object = (ipc_object_t) kmsg->ikm_header.msgh_local_port;
- if (IO_VALID(object))
- ipc_object_destroy(object, MACH_MSGH_BITS_LOCAL(mbits));
- if (mbits & MACH_MSGH_BITS_COMPLEX) {
- vm_offset_t saddr, eaddr;
- saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
- eaddr = (vm_offset_t) &kmsg->ikm_header +
- kmsg->ikm_header.msgh_size;
- ipc_kmsg_clean_body(saddr, eaddr);
- }
- }
- /*
- * Routine: ipc_kmsg_clean_partial
- * Purpose:
- * Cleans a partially-acquired kernel message.
- * eaddr is the address of the type specification
- * in the body of the message that contained the error.
- * If dolast, the memory and port rights in this last
- * type spec are also cleaned. In that case, number
- * specifies the number of port rights to clean.
- * Conditions:
- * Nothing locked.
- */
- void
- ipc_kmsg_clean_partial(
- ipc_kmsg_t kmsg,
- vm_offset_t eaddr,
- boolean_t dolast,
- mach_msg_type_number_t number)
- {
- ipc_object_t object;
- mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits;
- vm_offset_t saddr;
- assert(kmsg->ikm_marequest == IMAR_NULL);
- object = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
- assert(IO_VALID(object));
- ipc_object_destroy(object, MACH_MSGH_BITS_REMOTE(mbits));
- object = (ipc_object_t) kmsg->ikm_header.msgh_local_port;
- if (IO_VALID(object))
- ipc_object_destroy(object, MACH_MSGH_BITS_LOCAL(mbits));
- saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
- ipc_kmsg_clean_body(saddr, eaddr);
- if (dolast) {
- mach_msg_type_long_t *type;
- mach_msg_type_name_t name;
- mach_msg_type_size_t size;
- mach_msg_type_number_t rnumber;
- boolean_t is_inline, is_port;
- vm_size_t length;
- xxx: type = (mach_msg_type_long_t *) eaddr;
- is_inline = ((mach_msg_type_t*)type)->msgt_inline;
- if (((mach_msg_type_t*)type)->msgt_longform) {
- /* This must be aligned */
- if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
- (is_misaligned(type))) {
- eaddr = ptr_align(eaddr);
- goto xxx;
- }
- name = type->msgtl_name;
- size = type->msgtl_size;
- rnumber = type->msgtl_number;
- eaddr += sizeof(mach_msg_type_long_t);
- } else {
- name = ((mach_msg_type_t*)type)->msgt_name;
- size = ((mach_msg_type_t*)type)->msgt_size;
- rnumber = ((mach_msg_type_t*)type)->msgt_number;
- eaddr += sizeof(mach_msg_type_t);
- }
- /* padding (ptrs and ports) ? */
- if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
- ((size >> 3) == sizeof(natural_t)))
- eaddr = ptr_align(eaddr);
- /* calculate length of data in bytes, rounding up */
- length = ((rnumber * size) + 7) >> 3;
- is_port = MACH_MSG_TYPE_PORT_ANY(name);
- if (is_port) {
- ipc_object_t *objects;
- mach_msg_type_number_t i;
- objects = (ipc_object_t *)
- (is_inline ? eaddr : * (vm_offset_t *) eaddr);
- /* destroy port rights carried in the message */
- for (i = 0; i < number; i++) {
- ipc_object_t obj = objects[i];
- if (!IO_VALID(obj))
- continue;
- ipc_object_destroy(obj, name);
- }
- }
- if (!is_inline) {
- vm_offset_t data = * (vm_offset_t *) eaddr;
- /* destroy memory carried in the message */
- if (length == 0)
- assert(data == 0);
- else if (is_port)
- kfree(data, length);
- else
- vm_map_copy_discard((vm_map_copy_t) data);
- }
- }
- }
- /*
- * Routine: ipc_kmsg_free
- * Purpose:
- * Free a kernel message buffer.
- * Conditions:
- * Nothing locked.
- */
- void
- ipc_kmsg_free(ipc_kmsg_t kmsg)
- {
- vm_size_t size = kmsg->ikm_size;
- switch (size) {
- case IKM_SIZE_NETWORK:
- /* return it to the network code */
- net_kmsg_put(kmsg);
- break;
- default:
- kfree((vm_offset_t) kmsg, size);
- break;
- }
- }
- /*
- * Routine: ipc_kmsg_get
- * Purpose:
- * Allocates a kernel message buffer.
- * Copies a user message to the message buffer.
- * Conditions:
- * Nothing locked.
- * Returns:
- * MACH_MSG_SUCCESS Acquired a message buffer.
- * MACH_SEND_MSG_TOO_SMALL Message smaller than a header.
- * MACH_SEND_MSG_TOO_SMALL Message size not long-word multiple.
- * MACH_SEND_NO_BUFFER Couldn't allocate a message buffer.
- * MACH_SEND_INVALID_DATA Couldn't copy message data.
- */
- mach_msg_return_t
- ipc_kmsg_get(
- mach_msg_header_t *msg,
- mach_msg_size_t size,
- ipc_kmsg_t *kmsgp)
- {
- ipc_kmsg_t kmsg;
- if ((size < sizeof(mach_msg_header_t)) || (size & 3))
- return MACH_SEND_MSG_TOO_SMALL;
- if (size <= IKM_SAVED_MSG_SIZE) {
- kmsg = ikm_cache();
- if (kmsg != IKM_NULL) {
- ikm_cache() = IKM_NULL;
- ikm_check_initialized(kmsg, IKM_SAVED_KMSG_SIZE);
- } else {
- kmsg = ikm_alloc(IKM_SAVED_MSG_SIZE);
- if (kmsg == IKM_NULL)
- return MACH_SEND_NO_BUFFER;
- ikm_init(kmsg, IKM_SAVED_MSG_SIZE);
- }
- } else {
- kmsg = ikm_alloc(size);
- if (kmsg == IKM_NULL)
- return MACH_SEND_NO_BUFFER;
- ikm_init(kmsg, size);
- }
- if (copyinmsg(msg, &kmsg->ikm_header, size)) {
- ikm_free(kmsg);
- return MACH_SEND_INVALID_DATA;
- }
- kmsg->ikm_header.msgh_size = size;
- *kmsgp = kmsg;
- return MACH_MSG_SUCCESS;
- }
- /*
- * Routine: ipc_kmsg_get_from_kernel
- * Purpose:
- * Allocates a kernel message buffer.
- * Copies a kernel message to the message buffer.
- * Only resource errors are allowed.
- * Conditions:
- * Nothing locked.
- * Returns:
- * MACH_MSG_SUCCESS Acquired a message buffer.
- * MACH_SEND_NO_BUFFER Couldn't allocate a message buffer.
- */
- extern mach_msg_return_t
- ipc_kmsg_get_from_kernel(
- mach_msg_header_t *msg,
- mach_msg_size_t size,
- ipc_kmsg_t *kmsgp)
- {
- ipc_kmsg_t kmsg;
- assert(size >= sizeof(mach_msg_header_t));
- assert((size & 3) == 0);
- kmsg = ikm_alloc(size);
- if (kmsg == IKM_NULL)
- return MACH_SEND_NO_BUFFER;
- ikm_init(kmsg, size);
- memcpy(&kmsg->ikm_header, msg, size);
- kmsg->ikm_header.msgh_size = size;
- *kmsgp = kmsg;
- return MACH_MSG_SUCCESS;
- }
- /*
- * Routine: ipc_kmsg_put
- * Purpose:
- * Copies a message buffer to a user message.
- * Copies only the specified number of bytes.
- * Frees the message buffer.
- * Conditions:
- * Nothing locked. The message buffer must have clean
- * header (ikm_marequest) fields.
- * Returns:
- * MACH_MSG_SUCCESS Copied data out of message buffer.
- * MACH_RCV_INVALID_DATA Couldn't copy to user message.
- */
- mach_msg_return_t
- ipc_kmsg_put(
- mach_msg_header_t *msg,
- ipc_kmsg_t kmsg,
- mach_msg_size_t size)
- {
- mach_msg_return_t mr;
-
- printk(KERN_ERR,"ipc_kmsg_put is broken\n");
- return -1;//BUG here -- assert fails
- ikm_check_initialized(kmsg, kmsg->ikm_size);
- if (copyoutmsg(&kmsg->ikm_header, msg, size))
- mr = MACH_RCV_INVALID_DATA;
- else
- mr = MACH_MSG_SUCCESS;
- if ((kmsg->ikm_size == IKM_SAVED_KMSG_SIZE) &&
- (ikm_cache() == IKM_NULL))
- ikm_cache() = kmsg;
- else
- ikm_free(kmsg);
- return mr;
- }
- /*
- * Routine: ipc_kmsg_put_to_kernel
- * Purpose:
- * Copies a message buffer to a kernel message.
- * Frees the message buffer.
- * No errors allowed.
- * Conditions:
- * Nothing locked.
- */
- void
- ipc_kmsg_put_to_kernel(
- mach_msg_header_t *msg,
- ipc_kmsg_t kmsg,
- mach_msg_size_t size)
- {
- #if DIPC
- assert(!KMSG_IN_DIPC(kmsg));
- #endif /* DIPC */
- memcpy(msg, &kmsg->ikm_header, size);
- ikm_free(kmsg);
- }
- /*
- * Routine: ipc_kmsg_copyin_header
- * Purpose:
- * "Copy-in" port rights in the header of a message.
- * Operates atomically; if it doesn't succeed the
- * message header and the space are left untouched.
- * If it does succeed the remote/local port fields
- * contain object pointers instead of port names,
- * and the bits field is updated. The destination port
- * will be a valid port pointer.
- *
- * The notify argument implements the MACH_SEND_CANCEL option.
- * If it is not MACH_PORT_NULL, it should name a receive right.
- * If the processing of the destination port would generate
- * a port-deleted notification (because the right for the
- * destination port is destroyed and it had a request for
- * a dead-name notification registered), and the port-deleted
- * notification would be sent to the named receive right,
- * then it isn't sent and the send-once right for the notify
- * port is quietly destroyed.
- * Conditions:
- * Nothing locked.
- * Returns:
- * MACH_MSG_SUCCESS Successful copyin.
- * MACH_SEND_INVALID_HEADER
- * Illegal value in the message header bits.
- * MACH_SEND_INVALID_DEST The space is dead.
- * MACH_SEND_INVALID_NOTIFY
- * Notify is non-null and doesn't name a receive right.
- * (Either KERN_INVALID_NAME or KERN_INVALID_RIGHT.)
- * MACH_SEND_INVALID_DEST Can't copyin destination port.
- * (Either KERN_INVALID_NAME or KERN_INVALID_RIGHT.)
- * MACH_SEND_INVALID_REPLY Can't copyin reply port.
- * (Either KERN_INVALID_NAME or KERN_INVALID_RIGHT.)
- */
- mach_msg_return_t
- ipc_kmsg_copyin_header(
- mach_msg_header_t *msg,
- ipc_space_t space,
- mach_port_t notify)
- {
- mach_msg_bits_t mbits = msg->msgh_bits &~ MACH_MSGH_BITS_CIRCULAR;
- mach_port_t dest_name = msg->msgh_remote_port;
- mach_port_t reply_name = msg->msgh_local_port;
- kern_return_t kr;
- #ifndef MIGRATING_THREADS
- /* first check for common cases */
- if (notify == MACH_PORT_NULL) switch (MACH_MSGH_BITS_PORTS(mbits)) {
- case MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0): {
- ipc_entry_t entry;
- ipc_entry_bits_t bits;
- ipc_port_t dest_port;
- /* sending an asynchronous message */
- if (reply_name != MACH_PORT_NULL)
- break;
- is_read_lock(space);
- if (!space->is_active)
- goto abort_async;
- entry = ipc_entry_lookup (space, dest_name);
- if (entry == IE_NULL)
- goto abort_async;
- bits = entry->ie_bits;
- /* check type bits */
- if (IE_BITS_TYPE (bits) != MACH_PORT_TYPE_SEND)
- goto abort_async;
- /* optimized ipc_right_copyin */
- assert(IE_BITS_UREFS(bits) > 0);
- dest_port = (ipc_port_t) entry->ie_object;
- assert(dest_port != IP_NULL);
- ip_lock(dest_port);
- /* can unlock space now without compromising atomicity */
- is_read_unlock(space);
- if (!ip_active(dest_port)) {
- ip_unlock(dest_port);
- break;
- }
- assert(dest_port->ip_srights > 0);
- dest_port->ip_srights++;
- ip_reference(dest_port);
- ip_unlock(dest_port);
- msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
- MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND, 0));
- msg->msgh_remote_port = (mach_port_t) dest_port;
- return MACH_MSG_SUCCESS;
- abort_async:
- is_read_unlock(space);
- break;
- }
- case MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND,
- MACH_MSG_TYPE_MAKE_SEND_ONCE): {
- ipc_entry_t entry;
- ipc_entry_bits_t bits;
- ipc_port_t dest_port, reply_port;
- /* sending a request message */
- is_read_lock(space);
- if (!space->is_active)
- goto abort_request;
- entry = ipc_entry_lookup (space, dest_name);
- if (entry == IE_NULL)
- goto abort_request;
- bits = entry->ie_bits;
- /* check type bits */
- if (IE_BITS_TYPE (bits) != MACH_PORT_TYPE_SEND)
- goto abort_request;
- assert(IE_BITS_UREFS(bits) > 0);
- dest_port = (ipc_port_t) entry->ie_object;
- assert(dest_port != IP_NULL);
- entry = ipc_entry_lookup (space, reply_name);
- if (entry == IE_NULL)
- goto abort_request;
- bits = entry->ie_bits;
- /* check type bits */
- if (IE_BITS_TYPE (bits) != MACH_PORT_TYPE_RECEIVE)
- goto abort_request;
- reply_port = (ipc_port_t) entry->ie_object;
- assert(reply_port != IP_NULL);
- /*
- * To do an atomic copyin, need simultaneous
- * locks on both ports and the space. If
- * dest_port == reply_port, and simple locking is
- * enabled, then we will abort. Otherwise it's
- * OK to unlock twice.
- */
- ip_lock(dest_port);
- if (!ip_active(dest_port) || !ip_lock_try(reply_port)) {
- ip_unlock(dest_port);
- goto abort_request;
- }
- /* can unlock space now without compromising atomicity */
- is_read_unlock(space);
- assert(dest_port->ip_srights > 0);
- dest_port->ip_srights++;
- ip_reference(dest_port);
- ip_unlock(dest_port);
- assert(ip_active(reply_port));
- assert(reply_port->ip_receiver_name == reply_name);
- assert(reply_port->ip_receiver == space);
- reply_port->ip_sorights++;
- ip_reference(reply_port);
- ip_unlock(reply_port);
- msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
- MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND,
- MACH_MSG_TYPE_PORT_SEND_ONCE));
- msg->msgh_remote_port = (mach_port_t) dest_port;
- msg->msgh_local_port = (mach_port_t) reply_port;
- return MACH_MSG_SUCCESS;
- abort_request:
- is_read_unlock(space);
- break;
- }
- case MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE, 0): {
- ipc_entry_t entry;
- ipc_entry_bits_t bits;
- ipc_port_t dest_port;
- /* sending a reply message */
- if (reply_name != MACH_PORT_NULL)
- break;
- is_write_lock(space);
- if (!space->is_active)
- goto abort_reply;
- entry = ipc_entry_lookup (space, dest_name);
- if (entry == IE_NULL)
- goto abort_reply;
- bits = entry->ie_bits;
- /* check and type bits */
- if (IE_BITS_TYPE (bits) != MACH_PORT_TYPE_SEND_ONCE)
- goto abort_reply;
- /* optimized ipc_right_copyin */
- assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
- assert(IE_BITS_UREFS(bits) == 1);
- assert((bits & IE_BITS_MAREQUEST) == 0);
- if (entry->ie_request != 0)
- goto abort_reply;
- dest_port = (ipc_port_t) entry->ie_object;
- assert(dest_port != IP_NULL);
- ip_lock(dest_port);
- if (!ip_active(dest_port)) {
- ip_unlock(dest_port);
- goto abort_reply;
- }
- assert(dest_port->ip_sorights > 0);
- ip_unlock(dest_port);
- entry->ie_object = IO_NULL;
- ipc_entry_dealloc (space, dest_name, entry);
- is_write_unlock(space);
- msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
- MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE,
- 0));
- msg->msgh_remote_port = (mach_port_t) dest_port;
- return MACH_MSG_SUCCESS;
- abort_reply:
- is_write_unlock(space);
- break;
- }
- default:
- /* don't bother optimizing */
- break;
- }
- #endif /* MIGRATING_THREADS */
- {
- mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits);
- mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits);
- ipc_object_t dest_port, reply_port;
- ipc_port_t dest_soright, reply_soright;
- ipc_port_t notify_port = 0; /* '=0' to quiet gcc warnings */
- if (!MACH_MSG_TYPE_PORT_ANY_SEND(dest_type))
- return MACH_SEND_INVALID_HEADER;
- if ((reply_type == 0) ?
- (reply_name != MACH_PORT_NULL) :
- !MACH_MSG_TYPE_PORT_ANY_SEND(reply_type))
- return MACH_SEND_INVALID_HEADER;
- is_write_lock(space);
- if (!space->is_active)
- goto invalid_dest;
- if (notify != MACH_PORT_NULL) {
- ipc_entry_t entry;
- if (((entry = ipc_entry_lookup(space, notify)) == IE_NULL) ||
- ((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0)) {
- is_write_unlock(space);
- return MACH_SEND_INVALID_NOTIFY;
- }
- notify_port = (ipc_port_t) entry->ie_object;
- }
- if (dest_name == reply_name) {
- ipc_entry_t entry;
- mach_port_t name = dest_name;
- /*
- * Destination and reply ports are the same!
- * This is a little tedious to make atomic, because
- * there are 25 combinations of dest_type/reply_type.
- * However, most are easy. If either is move-sonce,
- * then there must be an error. If either are
- * make-send or make-sonce, then we must be looking
- * at a receive right so the port can't die.
- * The hard cases are the combinations of
- * copy-send and make-send.
- */
- entry = ipc_entry_lookup(space, name);
- if (entry == IE_NULL)
- goto invalid_dest;
- assert(reply_type != 0); /* because name not null */
- if (!ipc_right_copyin_check(space, name, entry, reply_type))
- goto invalid_reply;
- if ((dest_type == MACH_MSG_TYPE_MOVE_SEND_ONCE) ||
- (reply_type == MACH_MSG_TYPE_MOVE_SEND_ONCE)) {
- /*
- * Why must there be an error? To get a valid
- * destination, this entry must name a live
- * port (not a dead name or dead port). However
- * a successful move-sonce will destroy a
- * live entry. Therefore the other copyin,
- * whatever it is, would fail. We've already
- * checked for reply port errors above,
- * so report a destination error.
- */
- goto invalid_dest;
- } else if ((dest_type == MACH_MSG_TYPE_MAKE_SEND) ||
- (dest_type == MACH_MSG_TYPE_MAKE_SEND_ONCE) ||
- (reply_type == MACH_MSG_TYPE_MAKE_SEND) ||
- (reply_type == MACH_MSG_TYPE_MAKE_SEND_ONCE)) {
- kr = ipc_right_copyin(space, name, entry,
- dest_type, FALSE,
- &dest_port, &dest_soright);
- if (kr != KERN_SUCCESS)
- goto invalid_dest;
- /*
- * Either dest or reply needs a receive right.
- * We know the receive right is there, because
- * of the copyin_check and copyin calls. Hence
- * the port is not in danger of dying. If dest
- * used the receive right, then the right needed
- * by reply (and verified by copyin_check) will
- * still be there.
- */
- assert(IO_VALID(dest_port));
- assert(entry->ie_bits & MACH_PORT_TYPE_RECEIVE);
- assert(dest_soright == IP_NULL);
- kr = ipc_right_copyin(space, name, entry,
- reply_type, TRUE,
- &reply_port, &reply_soright);
- assert(kr == KERN_SUCCESS);
- assert(reply_port == dest_port);
- assert(entry->ie_bits & MACH_PORT_TYPE_RECEIVE);
- assert(reply_soright == IP_NULL);
- } else if ((dest_type == MACH_MSG_TYPE_COPY_SEND) &&
- (reply_type == MACH_MSG_TYPE_COPY_SEND)) {
- /*
- * To make this atomic, just do one copy-send,
- * and dup the send right we get out.
- */
- kr = ipc_right_copyin(space, name, entry,
- dest_type, FALSE,
- &dest_port, &dest_soright);
- if (kr != KERN_SUCCESS)
- goto invalid_dest;
- assert(entry->ie_bits & MACH_PORT_TYPE_SEND);
- assert(dest_soright == IP_NULL);
- /*
- * It's OK if the port we got is dead now,
- * so reply_port is IP_DEAD, because the msg
- * won't go anywhere anyway.
- */
- reply_port = (ipc_object_t)
- ipc_port_copy_send((ipc_port_t) dest_port);
- reply_soright = IP_NULL;
- } else if ((dest_type == MACH_MSG_TYPE_MOVE_SEND) &&
- (reply_type == MACH_MSG_TYPE_MOVE_SEND)) {
- /*
- * This is an easy case. Just use our
- * handy-dandy special-purpose copyin call
- * to get two send rights for the price of one.
- */
- kr = ipc_right_copyin_two(space, name, entry,
- &dest_port, &dest_soright);
- if (kr != KERN_SUCCESS)
- goto invalid_dest;
- /* the entry might need to be deallocated */
- if (IE_BITS_TYPE(entry->ie_bits)
- == MACH_PORT_TYPE_NONE)
- ipc_entry_dealloc(space, name, entry);
- reply_port = dest_port;
- reply_soright = IP_NULL;
- } else {
- ipc_port_t soright;
- assert(((dest_type == MACH_MSG_TYPE_COPY_SEND) &&
- (reply_type == MACH_MSG_TYPE_MOVE_SEND)) ||
- ((dest_type == MACH_MSG_TYPE_MOVE_SEND) &&
- (reply_type == MACH_MSG_TYPE_COPY_SEND)));
- /*
- * To make this atomic, just do a move-send,
- * and dup the send right we get out.
- */
- kr = ipc_right_copyin(space, name, entry,
- MACH_MSG_TYPE_MOVE_SEND, FALSE,
- &dest_port, &soright);
- if (kr != KERN_SUCCESS)
- goto invalid_dest;
- /* the entry might need to be deallocated */
- if (IE_BITS_TYPE(entry->ie_bits)
- == MACH_PORT_TYPE_NONE)
- ipc_entry_dealloc(space, name, entry);
- /*
- * It's OK if the port we got is dead now,
- * so reply_port is IP_DEAD, because the msg
- * won't go anywhere anyway.
- */
- reply_port = (ipc_object_t)
- ipc_port_copy_send((ipc_port_t) dest_port);
- if (dest_type == MACH_MSG_TYPE_MOVE_SEND) {
- dest_soright = soright;
- reply_soright = IP_NULL;
- } else {
- dest_soright = IP_NULL;
- reply_soright = soright;
- }
- }
- } else if (!MACH_PORT_VALID(reply_name)) {
- ipc_entry_t entry;
- /*
- * No reply port! This is an easy case
- * to make atomic. Just copyin the destination.
- */
- entry = ipc_entry_lookup(space, dest_name);
- if (entry == IE_NULL)
- goto invalid_dest;
- kr = ipc_right_copyin(space, dest_name, entry,
- dest_type, FALSE,
- &dest_port, &dest_soright);
- if (kr != KERN_SUCCESS)
- goto invalid_dest;
- /* the entry might need to be deallocated */
- if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE)
- ipc_entry_dealloc(space, dest_name, entry);
- reply_port = (ipc_object_t) reply_name;
- reply_soright = IP_NULL;
- } else {
- ipc_entry_t dest_entry, reply_entry;
- ipc_port_t saved_reply;
- /*
- * This is the tough case to make atomic.
- * The difficult problem is serializing with port death.
- * At the time we copyin dest_port, it must be alive.
- * If reply_port is alive when we copyin it, then
- * we are OK, because we serialize before the death
- * of both ports. Assume reply_port is dead at copyin.
- * Then if dest_port dies/died after reply_port died,
- * we are OK, because we serialize between the death
- * of the two ports. So the bad case is when dest_port
- * dies after its copyin, reply_port dies before its
- * copyin, and dest_port dies before reply_port. Then
- * the copyins operated as if dest_port was alive
- * and reply_port was dead, which shouldn't have happened
- * because they died in the other order.
- *
- * We handle the bad case by undoing the copyins
- * (which is only possible because the ports are dead)
- * and failing with MACH_SEND_INVALID_DEST, serializing
- * after the death of the ports.
- *
- * Note that it is easy for a user task to tell if
- * a copyin happened before or after a port died.
- * For example, suppose both dest and reply are
- * send-once rights (types are both move-sonce) and
- * both rights have dead-name requests registered.
- * If a port dies before copyin, a dead-name notification
- * is generated and the dead name's urefs are incremented,
- * and if the copyin happens first, a port-deleted
- * notification is generated.
- *
- * Note that although the entries are different,
- * dest_port and reply_port might still be the same.
- */
- dest_entry = ipc_entry_lookup(space, dest_name);
- if (dest_entry == IE_NULL)
- goto invalid_dest;
- reply_entry = ipc_entry_lookup(space, reply_name);
- if (reply_entry == IE_NULL)
- goto invalid_reply;
- assert(dest_entry != reply_entry); /* names are not equal */
- assert(reply_type != 0); /* because reply_name not null */
- if (!ipc_right_copyin_check(space, reply_name, reply_entry,
- reply_type))
- goto invalid_reply;
- kr = ipc_right_copyin(space, dest_name, dest_entry,
- dest_type, FALSE,
- &dest_port, &dest_soright);
- if (kr != KERN_SUCCESS)
- goto invalid_dest;
- assert(IO_VALID(dest_port));
- saved_reply = (ipc_port_t) reply_entry->ie_object;
- /* might be IP_NULL, if this is a dead name */
- if (saved_reply != IP_NULL)
- ipc_port_reference(saved_reply);
- kr = ipc_right_copyin(space, reply_name, reply_entry,
- reply_type, TRUE,
- &reply_port, &reply_soright);
- assert(kr == KERN_SUCCESS);
- if ((saved_reply != IP_NULL) && (reply_port == IO_DEAD)) {
- ipc_port_t dest = (ipc_port_t) dest_port;
- ipc_port_timestamp_t timestamp;
- boolean_t must_undo;
- /*
- * The reply port died before copyin.
- * Check if dest port died before reply.
- */
- ip_lock(saved_reply);
- assert(!ip_active(saved_reply));
- timestamp = saved_reply->ip_timestamp;
- ip_unlock(saved_reply);
- ip_lock(dest);
- must_undo = (!ip_active(dest) &&
- IP_TIMESTAMP_ORDER(dest->ip_timestamp,
- timestamp));
- ip_unlock(dest);
- if (must_undo) {
- /*
- * Our worst nightmares are realized.
- * Both destination and reply ports
- * are dead, but in the wrong order,
- * so we must undo the copyins and
- * possibly generate a dead-name notif.
- */
- ipc_right_copyin_undo(
- space, dest_name, dest_entry,
- dest_type, dest_port,
- dest_soright);
- /* dest_entry may be deallocated now */
- ipc_right_copyin_undo(
- space, reply_name, reply_entry,
- reply_type, reply_port,
- reply_soright);
- /* reply_entry may be deallocated now */
- is_write_unlock(space);
- if (dest_soright != IP_NULL)
- ipc_notify_dead_name(dest_soright,
- dest_name);
- assert(reply_soright == IP_NULL);
- ipc_port_release(saved_reply);
- return MACH_SEND_INVALID_DEST;
- }
- }
- /* the entries might need to be deallocated */
- if (IE_BITS_TYPE(reply_entry->ie_bits) == MACH_PORT_TYPE_NONE)
- ipc_entry_dealloc(space, reply_name, reply_entry);
- if (IE_BITS_TYPE(dest_entry->ie_bits) == MACH_PORT_TYPE_NONE)
- ipc_entry_dealloc(space, dest_name, dest_entry);
- if (saved_reply != IP_NULL)
- ipc_port_release(saved_reply);
- }
- /*
- * At this point, dest_port, reply_port,
- * dest_soright, reply_soright are all initialized.
- * Any defunct entries have been deallocated.
- * The space is still write-locked, and we need to
- * make the MACH_SEND_CANCEL check. The notify_port pointer
- * is still usable, because the copyin code above won't ever
- * deallocate a receive right, so its entry still exists
- * and holds a ref. Note notify_port might even equal
- * dest_port or reply_port.
- */
- if ((notify != MACH_PORT_NULL) &&
- (dest_soright == notify_port)) {
- ipc_port_release_sonce(dest_soright);
- dest_soright = IP_NULL;
- }
- is_write_unlock(space);
- if (dest_soright != IP_NULL)
- ipc_notify_port_deleted(dest_soright, dest_name);
- if (reply_soright != IP_NULL)
- ipc_notify_port_deleted(reply_soright, reply_name);
- dest_type = ipc_object_copyin_type(dest_type);
- reply_type = ipc_object_copyin_type(reply_type);
- msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
- MACH_MSGH_BITS(dest_type, reply_type));
- msg->msgh_remote_port = (mach_port_t) dest_port;
- msg->msgh_local_port = (mach_port_t) reply_port;
- }
- return MACH_MSG_SUCCESS;
- invalid_dest:
- is_write_unlock(space);
- return MACH_SEND_INVALID_DEST;
- invalid_reply:
- is_write_unlock(space);
- return MACH_SEND_INVALID_REPLY;
- }
- mach_msg_return_t
- ipc_kmsg_copyin_body(
- ipc_kmsg_t kmsg,
- ipc_space_t space,
- vm_map_t map)
- {
- ipc_object_t dest;
- vm_offset_t saddr, eaddr;
- boolean_t complex;
- boolean_t use_page_lists, steal_pages;
- dest = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
- complex = FALSE;
- use_page_lists = ipc_kobject_vm_page_list(ip_kotype((ipc_port_t)dest));
- steal_pages = ipc_kobject_vm_page_steal(ip_kotype((ipc_port_t)dest));
- saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
- eaddr = (vm_offset_t) &kmsg->ikm_header + kmsg->ikm_header.msgh_size;
- while (saddr < eaddr) {
- vm_offset_t taddr = saddr;
- mach_msg_type_long_t *type;
- mach_msg_type_name_t name;
- mach_msg_type_size_t size;
- mach_msg_type_number_t number;
- boolean_t is_inline, longform, dealloc, is_port;
- vm_offset_t data;
- uint64_t length;
- kern_return_t kr;
- type = (mach_msg_type_long_t *) saddr;
- if (((eaddr - saddr) < sizeof(mach_msg_type_t)) ||
- ((longform = ((mach_msg_type_t*)type)->msgt_longform) &&
- ((eaddr - saddr) < sizeof(mach_msg_type_long_t)))) {
- ipc_kmsg_clean_partial(kmsg, taddr, FALSE, 0);
- return MACH_SEND_MSG_TOO_SMALL;
- }
- is_inline = ((mach_msg_type_t*)type)->msgt_inline;
- dealloc = ((mach_msg_type_t*)type)->msgt_deallocate;
- if (longform) {
- /* This must be aligned */
- if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
- (is_misaligned(type))) {
- saddr = ptr_align(saddr);
- continue;
- }
- name = type->msgtl_name;
- size = type->msgtl_size;
- number = type->msgtl_number;
- saddr += sizeof(mach_msg_type_long_t);
- } else {
- name = ((mach_msg_type_t*)type)->msgt_name;
- size = ((mach_msg_type_t*)type)->msgt_size;
- number = ((mach_msg_type_t*)type)->msgt_number;
- saddr += sizeof(mach_msg_type_t);
- }
- is_port = MACH_MSG_TYPE_PORT_ANY(name);
- if ((is_port && (size != PORT_T_SIZE_IN_BITS)) ||
- (longform && ((type->msgtl_header.msgt_name != 0) ||
- (type->msgtl_header.msgt_size != 0) ||
- (type->msgtl_header.msgt_number != 0))) ||
- (((mach_msg_type_t*)type)->msgt_unused != 0) ||
- (dealloc && is_inline)) {
- ipc_kmsg_clean_partial(kmsg, taddr, FALSE, 0);
- return MACH_SEND_INVALID_TYPE;
- }
- /* padding (ptrs and ports) ? */
- if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
- ((size >> 3) == sizeof(natural_t)))
- saddr = ptr_align(saddr);
- /* calculate length of data in bytes, rounding up */
- length = (((uint64_t) number * size) + 7) >> 3;
- if (is_inline) {
- vm_size_t amount;
- /* inline data sizes round up to int boundaries */
- amount = (length + 3) &~ 3;
- if ((eaddr - saddr) < amount) {
- ipc_kmsg_clean_partial(kmsg, taddr, FALSE, 0);
- return MACH_SEND_MSG_TOO_SMALL;
- }
- data = saddr;
- saddr += amount;
- } else {
- vm_offset_t addr;
- if (sizeof(vm_offset_t) > sizeof(mach_msg_type_t))
- saddr = ptr_align(saddr);
- if ((eaddr - saddr) < sizeof(vm_offset_t)) {
- ipc_kmsg_clean_partial(kmsg, taddr, FALSE, 0);
- return MACH_SEND_MSG_TOO_SMALL;
- }
- /* grab the out-of-line data */
- addr = * (vm_offset_t *) saddr;
- if (length == 0)
- data = 0;
- else if (is_port) {
- data = kalloc(length);
- if (data == 0)
- goto invalid_memory;
- if (copyinmap(map, (char *) addr,
- (char *) data, length) ||
- (dealloc &&
- (vm_deallocate(map, addr, length) !=
- KERN_SUCCESS))) {
- kfree(data, length);
- goto invalid_memory;
- }
- } else {
- vm_map_copy_t copy;
- if (use_page_lists) {
- kr = vm_map_copyin_page_list(map,
- addr, length, dealloc,
- steal_pages, ©, FALSE);
- } else {
- kr = vm_map_copyin(map, addr, length,
- dealloc, ©);
- }
- if (kr != KERN_SUCCESS) {
- invalid_memory:
- ipc_kmsg_clean_partial(kmsg, taddr,
- FALSE, 0);
- return MACH_SEND_INVALID_MEMORY;
- }
- data = (vm_offset_t) copy;
- }
- * (vm_offset_t *) saddr = data;
- saddr += sizeof(vm_offset_t);
- complex = TRUE;
- }
- if (is_port) {
- mach_msg_type_name_t newname =
- ipc_object_copyin_type(name);
- ipc_object_t *objects = (ipc_object_t *) data;
- mach_msg_type_number_t i;
- if (longform)
- type->msgtl_name = newname;
- else
- ((mach_msg_type_t*)type)->msgt_name = newname;
- for (i = 0; i < number; i++) {
- mach_port_t port = (mach_port_t) objects[i];
- ipc_object_t object;
- if (!MACH_PORT_VALID(port))
- continue;
- kr = ipc_object_copyin(space, port,
- name, &object);
- if (kr != KERN_SUCCESS) {
- ipc_kmsg_clean_partial(kmsg, taddr,
- TRUE, i);
- return MACH_SEND_INVALID_RIGHT;
- }
- if ((newname == MACH_MSG_TYPE_PORT_RECEIVE) &&
- ipc_port_check_circularity(
- (ipc_port_t) object,
- (ipc_port_t) dest))
- kmsg->ikm_header.msgh_bits |=
- MACH_MSGH_BITS_CIRCULAR;
- objects[i] = object;
- }
- complex = TRUE;
- }
- }
- if (!complex)
- kmsg->ikm_header.msgh_bits &= ~MACH_MSGH_BITS_COMPLEX;
- return MACH_MSG_SUCCESS;
- }
- /*
- * Routine: ipc_kmsg_copyin
- * Purpose:
- * "Copy-in" port rights and out-of-line memory
- * in the message.
- *
- * In all failure cases, the message is left holding
- * no rights or memory. However, the message buffer
- * is not deallocated. If successful, the message
- * contains a valid destination port.
- * Conditions:
- * Nothing locked.
- * Returns:
- * MACH_MSG_SUCCESS Successful copyin.
- * MACH_SEND_INVALID_HEADER
- * Illegal value in the message header bits.
- * MACH_SEND_INVALID_NOTIFY Bad notify port.
- * MACH_SEND_INVALID_DEST Can't copyin destination port.
- * MACH_SEND_INVALID_REPLY Can't copyin reply port.
- * MACH_SEND_INVALID_MEMORY Can't grab out-of-line memory.
- * MACH_SEND_INVALID_RIGHT Can't copyin port right in body.
- * MACH_SEND_INVALID_TYPE Bad type specification.
- * MACH_SEND_MSG_TOO_SMALL Body is too small for types/data.
- */
- mach_msg_return_t
- ipc_kmsg_copyin(
- ipc_kmsg_t kmsg,
- ipc_space_t space,
- vm_map_t map,
- mach_port_t notify)
- {
- mach_msg_return_t mr;
- mr = ipc_kmsg_copyin_header(&kmsg->ikm_header, space, notify);
- if (mr != MACH_MSG_SUCCESS)
- return mr;
- if ((kmsg->ikm_header.msgh_bits & MACH_MSGH_BITS_COMPLEX) == 0)
- return MACH_MSG_SUCCESS;
- return ipc_kmsg_copyin_body(kmsg, space, map);
- }
- /*
- * Routine: ipc_kmsg_copyin_from_kernel
- * Purpose:
- * "Copy-in" port rights and out-of-line memory
- * in a message sent from the kernel.
- *
- * Because the message comes from the kernel,
- * the implementation assumes there are no errors
- * or peculiarities in the message.
- *
- * Returns TRUE if queueing the message
- * would result in a circularity.
- * Conditions:
- * Nothing locked.
- */
- void
- ipc_kmsg_copyin_from_kernel(ipc_kmsg_t kmsg)
- {
- mach_msg_bits_t bits = kmsg->ikm_header.msgh_bits;
- mach_msg_type_name_t rname = MACH_MSGH_BITS_REMOTE(bits);
- mach_msg_type_name_t lname = MACH_MSGH_BITS_LOCAL(bits);
- ipc_object_t remote = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
- ipc_object_t local = (ipc_object_t) kmsg->ikm_header.msgh_local_port;
- vm_offset_t saddr, eaddr;
- /* translate the destination and reply ports */
- ipc_object_copyin_from_kernel(remote, rname);
- if (IO_VALID(local))
- ipc_object_copyin_from_kernel(local, lname);
- /*
- * The common case is a complex message with no reply port,
- * because that is what the memory_object interface uses.
- */
- if (bits == (MACH_MSGH_BITS_COMPLEX |
- MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0))) {
- bits = (MACH_MSGH_BITS_COMPLEX |
- MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND, 0));
- kmsg->ikm_header.msgh_bits = bits;
- } else {
- bits = (MACH_MSGH_BITS_OTHER(bits) |
- MACH_MSGH_BITS(ipc_object_copyin_type(rname),
- ipc_object_copyin_type(lname)));
- kmsg->ikm_header.msgh_bits = bits;
- if ((bits & MACH_MSGH_BITS_COMPLEX) == 0)
- return;
- }
- saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
- eaddr = (vm_offset_t) &kmsg->ikm_header + kmsg->ikm_header.msgh_size;
- while (saddr < eaddr) {
- mach_msg_type_long_t *type;
- mach_msg_type_name_t name;
- mach_msg_type_size_t size;
- mach_msg_type_number_t number;
- boolean_t is_inline, longform, is_port;
- vm_offset_t data;
- vm_size_t length;
- type = (mach_msg_type_long_t *) saddr;
- is_inline = ((mach_msg_type_t*)type)->msgt_inline;
- longform = ((mach_msg_type_t*)type)->msgt_longform;
- /* type->msgtl_header.msgt_deallocate not used */
- if (longform) {
- /* This must be aligned */
- if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
- (is_misaligned(type))) {
- saddr = ptr_align(saddr);
- continue;
- }
- name = type->msgtl_name;
- size = type->msgtl_size;
- number = type->msgtl_number;
- saddr += sizeof(mach_msg_type_long_t);
- } else {
- name = ((mach_msg_type_t*)type)->msgt_name;
- size = ((mach_msg_type_t*)type)->msgt_size;
- number = ((mach_msg_type_t*)type)->msgt_number;
- saddr += sizeof(mach_msg_type_t);
- }
- /* padding (ptrs and ports) ? */
- if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
- ((size >> 3) == sizeof(natural_t)))
- saddr = ptr_align(saddr);
- /* calculate length of data in bytes, rounding up */
- length = ((number * size) + 7) >> 3;
- is_port = MACH_MSG_TYPE_PORT_ANY(name);
- if (is_inline) {
- /* inline data sizes round up to int boundaries */
- data = saddr;
- saddr += (length + 3) &~ 3;
- } else {
- /*
- * The sender should supply ready-made memory
- * for us, so we don't need to do anything.
- */
- data = * (vm_offset_t *) saddr;
- saddr += sizeof(vm_offset_t);
- }
- if (is_port) {
- mach_msg_type_name_t newname =
- ipc_object_copyin_type(name);
- ipc_object_t *objects = (ipc_object_t *) data;
- mach_msg_type_number_t i;
- if (longform)
- type->msgtl_name = newname;
- else
- ((mach_msg_type_t*)type)->msgt_name = newname;
- for (i = 0; i < number; i++) {
- ipc_object_t object = objects[i];
- if (!IO_VALID(object))
- continue;
- ipc_object_copyin_from_kernel(object, name);
- if ((newname == MACH_MSG_TYPE_PORT_RECEIVE) &&
- ipc_port_check_circularity(
- (ipc_port_t) object,
- (ipc_port_t) remote))
- kmsg->ikm_header.msgh_bits |=
- MACH_MSGH_BITS_CIRCULAR;
- }
- }
- }
- }
- /*
- * Routine: ipc_kmsg_copyout_header
- * Purpose:
- * "Copy-out" port rights in the header of a message.
- * Operates atomically; if it doesn't succeed the
- * message header and the space are left untouched.
- * If it does succeed the remote/local port fields
- * contain port names instead of object pointers,
- * and the bits field is updated.
- *
- * The notify argument implements the MACH_RCV_NOTIFY option.
- * If it is not MACH_PORT_NULL, it should name a receive right.
- * If the process of receiving the reply port creates a
- * new right in the receiving task, then the new right is
- * automatically registered for a dead-name notification,
- * with the notify port supplying the send-once right.
- * Conditions:
- * Nothing locked.
- * Returns:
- * MACH_MSG_SUCCESS Copied out port rights.
- * MACH_RCV_INVALID_NOTIFY
- * Notify is non-null and doesn't name a receive right.
- * (Either KERN_INVALID_NAME or KERN_INVALID_RIGHT.)
- * MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_SPACE
- * The space is dead.
- * MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_SPACE
- * No room in space for another name.
- * MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_KERNEL
- * Couldn't allocate memory for the reply port.
- * MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_KERNEL
- * Couldn't allocate memory for the dead-name request.
- */
- mach_msg_return_t
- ipc_kmsg_copyout_header(
- mach_msg_header_t *msg,
- ipc_space_t space,
- mach_port_t notify)
- {
- mach_msg_bits_t mbits = msg->msgh_bits;
- ipc_port_t dest = (ipc_port_t) msg->msgh_remote_port;
-
- printk(KERN_ERR,"ipc_kmsg_copyout_header is broken\n");
- return -1;//BUG here -- assert fails
- assert(IP_VALID(dest));
- #ifndef MIGRATING_THREADS
- /* first check for common cases */
- if (notify == MACH_PORT_NULL) switch (MACH_MSGH_BITS_PORTS(mbits)) {
- case MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND, 0): {
- mach_port_t dest_name;
- ipc_port_t nsrequest;
- unsigned long payload;
- /* receiving an asynchronous message */
- ip_lock(dest);
- if (!ip_active(dest)) {
- ip_unlock(dest);
- break;
- }
- /* optimized ipc_object_copyout_dest */
- assert(dest->ip_srights > 0);
- ip_release(dest);
- if (dest->ip_receiver == space)
- dest_name = dest->ip_receiver_name;
- else
- dest_name = MACH_PORT_NULL;
- payload = dest->ip_protected_payload;
- if ((--dest->ip_srights == 0) &&
- ((nsrequest = dest->ip_nsrequest) != IP_NULL)) {
- mach_port_mscount_t mscount;
- dest->ip_nsrequest = IP_NULL;
- mscount = dest->ip_mscount;
- ip_unlock(dest);
- ipc_notify_no_senders(nsrequest, mscount);
- } else
- ip_unlock(dest);
- if (! ipc_port_flag_protected_payload(dest)) {
- msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
- MACH_MSGH_BITS(0, MACH_MSG_TYPE_PORT_SEND));
- msg->msgh_local_port = dest_name;
- } else {
- msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
- MACH_MSGH_BITS(
- 0, MACH_MSG_TYPE_PROTECTED_PAYLOAD));
- msg->msgh_protected_payload = payload;
- }
- msg->msgh_remote_port = MACH_PORT_NULL;
- return MACH_MSG_SUCCESS;
- }
- case MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND,
- MACH_MSG_TYPE_PORT_SEND_ONCE): {
- ipc_entry_t entry;
- ipc_port_t reply = (ipc_port_t) msg->msgh_local_port;
- mach_port_t dest_name, reply_name;
- ipc_port_t nsrequest;
- unsigned long payload;
- /* receiving a request message */
- if (!IP_VALID(reply))
- break;
- is_write_lock(space);
- if (!space->is_active /*|| space->is_free_list == NULL*/) {
- printk(KERN_CRIT "!space->is_active || space->is_free_list == NULL\n");
- is_write_unlock(space);
- break;
- }
-
- /*
- * To do an atomic copyout, need simultaneous
- * locks on both ports and the space. If
- * dest == reply, and simple locking is
- * enabled, then we will abort. Otherwise it's
- * OK to unlock twice.
- */
- ip_lock(dest);
- if (!ip_active(dest) || !ip_lock_try(reply)) {
- ip_unlock(dest);
- is_write_unlock(space);
- break;
- }
- if (!ip_active(reply)) {
- ip_unlock(reply);
- ip_unlock(dest);
- is_write_unlock(space);
- break;
- }
- assert(reply->ip_sorights > 0);
- ip_unlock(reply);
- kern_return_t kr;
- kr = ipc_entry_get (space, &reply_name, &entry);
- if (kr) {
- ip_unlock(reply);
- ip_unlock(dest);
- is_write_unlock(space);
- break;
- }
- {
- mach_port_gen_t gen;
- assert((entry->ie_bits &~ IE_BITS_GEN_MASK) == 0);
- gen = entry->ie_bits + IE_BITS_GEN_ONE;
- /* optimized ipc_right_copyout */
- entry->ie_bits = gen | (MACH_PORT_TYPE_SEND_ONCE | 1);
- }
- assert(MACH_PORT_VALID(reply_name));
- entry->ie_object = (ipc_object_t) reply;
- is_write_unlock(space);
- /* optimized ipc_object_copyout_dest */
- assert(dest->ip_srights > 0);
- ip_release(dest);
- if (dest->ip_receiver == space)
- dest_name = dest->ip_receiver_name;
- else
- dest_name = MACH_PORT_NULL;
- payload = dest->ip_protected_payload;
- if ((--dest->ip_srights == 0) &&
- ((nsrequest = dest->ip_nsrequest) != IP_NULL)) {
- mach_port_mscount_t mscount;
- dest->ip_nsrequest = IP_NULL;
- mscount = dest->ip_mscount;
- ip_unlock(dest);
- ipc_notify_no_senders(nsrequest, mscount);
- } else
- ip_unlock(dest);
- if (! ipc_port_flag_protected_payload(dest)) {
- msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
- MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE,
- MACH_MSG_TYPE_PORT_SEND));
- msg->msgh_local_port = dest_name;
- } else {
- msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
- MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE,
- MACH_MSG_TYPE_PROTECTED_PAYLOAD));
- msg->msgh_protected_payload = payload;
- }
- msg->msgh_remote_port = reply_name;
- return MACH_MSG_SUCCESS;
- }
- case MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, 0): {
- mach_port_t dest_name;
- unsigned long payload;
- /* receiving a reply message */
- ip_lock(dest);
- if (!ip_active(dest)) {
- ip_unlock(dest);
- break;
- }
- /* optimized ipc_object_copyout_dest */
- assert(dest->ip_sorights > 0);
- payload = dest->ip_protected_payload;
- if (dest->ip_receiver == space) {
- ip_release(dest);
- dest->ip_sorights--;
- dest_name = dest->ip_receiver_name;
- ip_unlock(dest);
- } else {
- ip_unlock(dest);
- ipc_notify_send_once(dest);
- dest_name = MACH_PORT_NULL;
- }
- if (! ipc_port_flag_protected_payload(dest)) {
- msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
- MACH_MSGH_BITS(0,
- MACH_MSG_TYPE_PORT_SEND_ONCE));
- msg->msgh_local_port = dest_name;
- } else {
- msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
- MACH_MSGH_BITS(0,
- MACH_MSG_TYPE_PROTECTED_PAYLOAD));
- msg->msgh_protected_payload = payload;
- }
- msg->msgh_remote_port = MACH_PORT_NULL;
- return MACH_MSG_SUCCESS;
- }
- default:
- /* don't bother optimizing */
- break;
- }
- #endif /* MIGRATING_THREADS */
- {
- mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits);
- mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits);
- ipc_port_t reply = (ipc_port_t) msg->msgh_local_port;
- mach_port_t dest_name, reply_name;
- unsigned long payload;
- if (IP_VALID(reply)) {
- ipc_port_t notify_port;
- ipc_entry_t entry;
- kern_return_t kr;
- /*
- * Handling notify (for MACH_RCV_NOTIFY) is tricky.
- * The problem is atomically making a send-once right
- * from the notify port and installing it for a
- * dead-name request in the new entry, because this
- * requires two port locks (on the notify port and
- * the reply port). However, we can safely make
- * and consume send-once rights for the notify port
- * as long as we hold the space locked. This isn't
- * an atomicity problem, because the only way
- * to detect that a send-once right has been created
- * and then consumed if it wasn't needed is by getting
- * at the receive right to look at ip_sorights, and
- * because the space is write-locked status calls can't
- * lookup the notify port receive right. When we make
- * the send-once right, we lock the notify port,
- * so any status calls in progress will be done.
- */
- is_write_lock(space);
- for (;;) {
- ipc_port_request_index_t request;
- if (!space->is_active) {
- is_write_unlock(space);
- return (MACH_RCV_HEADER_ERROR|
- MACH_MSG_IPC_SPACE);
- }
- if (notify != MACH_PORT_NULL) {
- notify_port = ipc_port_lookup_notify(space,
- notify);
- if (notify_port == IP_NULL) {
- is_write_unlock(space);
- return MACH_RCV_INVALID_NOTIFY;
- }
- } else
- notify_port = IP_NULL;
- if ((reply_type != MACH_MSG_TYPE_PORT_SEND_ONCE) &&
- ipc_right_reverse(space, (ipc_object_t) reply,
- &reply_name, &entry)) {
- /* reply port is locked and active */
- /*
- * We don't need the notify_port
- * send-once right, but we can't release
- * it here because reply port is locked.
- * Wait until after the copyout to
- * release the notify port right.
- */
- assert(entry->ie_bits &
- MACH_PORT_TYPE_SEND_RECEIVE);
- break;
- }
- ip_lock(reply);
- if (!ip_active(reply)) {
- ip_release(reply);
- ip_check_unlock(reply);
- if (notify_port != IP_NULL)
- ipc_port_release_sonce(notify_port);
- ip_lock(dest);
- is_write_unlock(space);
- reply = IP_DEAD;
- reply_name = MACH_PORT_DEAD;
- goto copyout_dest;
- }
- kr = ipc_entry_alloc(space, &reply_name, &entry);
- if (kr != KERN_SUCCESS) {
- ip_unlock(reply);
- if (notify_port != IP_NULL)
- ipc_port_release_sonce(notify_port);
- is_write_unlock(space);
- if (kr == KERN_RESOURCE_SHORTAGE)
- return (MACH_RCV_HEADER_ERROR|
- MACH_MSG_IPC_KERNEL);
- else
- return (MACH_RCV_HEADER_ERROR|
- MACH_MSG_IPC_SPACE);
- }
- assert(IE_BITS_TYPE(entry->ie_bits)
- == MACH_PORT_TYPE_NONE);
- assert(entry->ie_object == IO_NULL);
- if (notify_port == IP_NULL) {
- /* not making a dead-name request */
- entry->ie_object = (ipc_object_t) reply;
- break;
- }
- kr = ipc_port_dnrequest(reply, reply_name,
- notify_port, &request);
- if (kr != KERN_SUCCESS) {
- ip_unlock(reply);
- ipc_port_release_sonce(notify_port);
- ipc_entry_dealloc(space, reply_name, entry);
- is_write_unlock(space);
- ip_lock(reply);
- if (!ip_active(reply)) {
- /* will fail next time around loop */
- ip_unlock(reply);
- is_write_lock(space);
- continue;
- }
- kr = ipc_port_dngrow(reply);
- /* port is unlocked */
- if (kr != KERN_SUCCESS)
- return (MACH_RCV_HEADER_ERROR|
- MACH_MSG_IPC_KERNEL);
- is_write_lock(space);
- continue;
- }
- notify_port = IP_NULL; /* don't release right below */
- entry->ie_object = (ipc_object_t) reply;
- entry->ie_request = request;
- break;
- }
- /* space and reply port are locked and active */
- ip_reference(reply); /* hold onto the reply port */
- kr = ipc_right_copyout(space, reply_name, entry,
- reply_type, TRUE, (ipc_object_t) reply);
- /* reply port is unlocked */
- assert(kr == KERN_SUCCESS);
- if (notify_port != IP_NULL)
- ipc_port_release_sonce(notify_port);
- ip_lock(dest);
- is_write_unlock(space);
- } else {
- /*
- * No reply port! This is an easy case.
- * We only need to have the space locked
- * when checking notify and when locking
- * the destination (to ensure atomicity).
- */
- is_read_lock(space);
- if (!space->is_active) {
- is_read_unlock(space);
- return MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_SPACE;
- }
- if (notify != MACH_PORT_NULL) {
- ipc_entry_t entry;
- /* must check notify even though it won't be used */
- if (((entry = ipc_entry_lookup(space, notify))
- == IE_NULL) ||
- ((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0)) {
- is_read_unlock(space);
- return MACH_RCV_INVALID_NOTIFY;
- }
- }
- ip_lock(dest);
- is_read_unlock(space);
- reply_name = (mach_port_t) reply;
- }
- /*
- * At this point, the space is unlocked and the destination
- * port is locked. (Lock taken while space was locked.)
- * reply_name is taken care of; we still need dest_name.
- * We still hold a ref for reply (if it is valid).
- *
- * If the space holds receive rights for the destination,
- * we return its name for the right. Otherwise the task
- * managed to destroy or give away the receive right between
- * receiving the message and this copyout. If the destination
- * is dead, return MACH_PORT_DEAD, and if the receive right
- * exists somewhere else (another space, in transit)
- * return MACH_PORT_NULL.
- *
- * Making this copyout operation atomic with the previous
- * copyout of the reply port is a bit tricky. If there was
- * no real reply port (it wasn't IP_VALID) then this isn't
- * an issue. If the reply port was dead at copyout time,
- * then we are OK, because if dest is dead we serialize
- * after the death of both ports and if dest is alive
- * we serialize after reply died but before dest's (later) death.
- * So assume reply was alive when we copied it out. If dest
- * is alive, then we are OK because we serialize before
- * the ports' deaths. So assume dest is dead when we look at it.
- * If reply dies/died after dest, then we are OK because
- * we serialize after dest died but before reply dies.
- * So the hard case is when reply is alive at copyout,
- * dest is dead at copyout, and reply died before dest died.
- * In this case pretend that dest is still alive, so
- * we serialize while both ports are alive.
- *
- * Because the space lock is held across the copyout of reply
- * and locking dest, the receive right for dest can't move
- * in or out of the space while the copyouts happen, so
- * that isn't an atomicity problem. In the last hard case
- * above, this implies that when dest is dead that the
- * space couldn't have had receive rights for dest at
- * the time reply was copied-out, so when we pretend
- * that dest is still alive, we can return MACH_PORT_NULL.
- *
- * If dest == reply, then we have to make it look like
- * either both copyouts happened before the port died,
- * or both happened after the port died. This special
- * case works naturally if the timestamp comparison
- * is done correctly.
- */
- copyout_dest:
- payload = dest->ip_protected_payload;
- if (ip_active(dest)) {
- ipc_object_copyout_dest(space, (ipc_object_t) dest,
- dest_type, &dest_name);
- /* dest is unlocked */
- } else {
- ipc_port_timestamp_t timestamp;
- timestamp = dest->ip_timestamp;
- ip_release(dest);
- ip_check_unlock(dest);
- if (IP_VALID(reply)) {
- ip_lock(reply);
- if (ip_active(reply) ||
- IP_TIMESTAMP_ORDER(timestamp,
- reply->ip_timestamp))
- dest_name = MACH_PORT_DEAD;
- else
- dest_name = MACH_PORT_NULL;
- ip_unlock(reply);
- } else
- dest_name = MACH_PORT_DEAD;
- }
- if (IP_VALID(reply))
- ipc_port_release(reply);
- if (! ipc_port_flag_protected_payload(dest)) {
- msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
- MACH_MSGH_BITS(reply_type, dest_type));
- msg->msgh_local_port = dest_name;
- } else {
- msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
- MACH_MSGH_BITS(reply_type,
- MACH_MSG_TYPE_PROTECTED_PAYLOAD));
- msg->msgh_protected_payload = payload;
- }
- msg->msgh_remote_port = reply_name;
- }
- return MACH_MSG_SUCCESS;
- }
- /*
- * Routine: ipc_kmsg_copyout_object
- * Purpose:
- * Copy-out a port right. Always returns a name,
- * even for unsuccessful return codes. Always
- * consumes the supplied object.
- * Conditions:
- * Nothing locked.
- * Returns:
- * MACH_MSG_SUCCESS The space acquired the right
- * (name is valid) or the object is dead (MACH_PORT_DEAD).
- * MACH_MSG_IPC_SPACE No room in space for the right,
- * or the space is dead. (Name is MACH_PORT_NULL.)
- * MACH_MSG_IPC_KERNEL Kernel resource shortage.
- * (Name is MACH_PORT_NULL.)
- */
- #if 0
- mach_msg_return_t
- ipc_kmsg_copyout_object(
- ipc_space_t space,
- ipc_object_t object,
- mach_msg_type_name_t msgt_name,
- mach_port_t *namep)
- {
- if (!IO_VALID(object)) {
- *namep = (mach_port_t) object;
- return MACH_MSG_SUCCESS;
- }
- #ifndef MIGRATING_THREADS
- /*
- * Attempt quick copyout of send rights. We optimize for a
- * live port for which the receiver holds send (and not
- * receive) rights in his local table.
- */
- if (msgt_name != MACH_MSG_TYPE_PORT_SEND)
- goto slow_copyout;
- {
- ipc_port_t port = (ipc_port_t) object;
- ipc_entry_t entry;
- is_write_lock(space);
- if (!space->is_active) {
- is_write_unlock(space);
- goto slow_copyout;
- }
- ip_lock(port);
- if (!ip_active(port) ||
- (entry = ipc_reverse_lookup(space,
- (ipc_object_t) port)) == NULL) {
- ip_unlock(port);
- is_write_unlock(space);
- goto slow_copyout;
- }
- *namep = entry->ie_name;
- /*
- * Copyout the send right, incrementing urefs
- * unless it would overflow, and consume the right.
- */
- assert(port->ip_srights > 1);
- port->ip_srights--;
- ip_release(port);
- ip_unlock(port);
- assert(entry->ie_bits & MACH_PORT_TYPE_SEND);
- assert(IE_BITS_UREFS(entry->ie_bits) > 0);
- assert(IE_BITS_UREFS(entry->ie_bits) < MACH_PORT_UREFS_MAX);
- {
- ipc_entry_bits_t bits = entry->ie_bits + 1;
- if (IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX)
- entry->ie_bits = bits;
- }
- is_write_unlock(space);
- return MACH_MSG_SUCCESS;
- }
- slow_copyout:
- #endif /* MIGRATING_THREADS */
- {
- kern_return_t kr;
- kr = ipc_object_copyout(space, object, msgt_name, TRUE, namep);
- if (kr != KERN_SUCCESS) {
- ipc_object_destroy(object, msgt_name);
- if (kr == KERN_INVALID_CAPABILITY)
- *namep = MACH_PORT_DEAD;
- else {
- *namep = MACH_PORT_NULL;
- if (kr == KERN_RESOURCE_SHORTAGE)
- return MACH_MSG_IPC_KERNEL;
- else
- return MACH_MSG_IPC_SPACE;
- }
- }
- return MACH_MSG_SUCCESS;
- }
- }
- #endif
- /*
- * Routine: ipc_kmsg_copyout_body
- * Purpose:
- * "Copy-out" port rights and out-of-line memory
- * in the body of a message.
- *
- * The error codes are a combination of special bits.
- * The copyout proceeds despite errors.
- * Conditions:
- * Nothing locked.
- * Returns:
- * MACH_MSG_SUCCESS Successful copyout.
- * MACH_MSG_IPC_SPACE No room for port right in name space.
- * MACH_MSG_VM_SPACE No room for memory in address space.
- * MACH_MSG_IPC_KERNEL Resource shortage handling port right.
- * MACH_MSG_VM_KERNEL Resource shortage handling memory.
- */
- mach_msg_return_t
- ipc_kmsg_copyout_body(
- vm_offset_t saddr,
- vm_offset_t eaddr,
- ipc_space_t space,
- vm_map_t map)
- {
- mach_msg_return_t mr = MACH_MSG_SUCCESS;
- kern_return_t kr;
- while (saddr < eaddr) {
- vm_offset_t taddr = saddr;
- mach_msg_type_long_t *type;
- mach_msg_type_name_t name;
- mach_msg_type_size_t size;
- mach_msg_type_number_t number;
- boolean_t is_inline, longform, is_port;
- uint64_t length;
- vm_offset_t addr;
- type = (mach_msg_type_long_t *) saddr;
- is_inline = ((mach_msg_type_t*)type)->msgt_inline;
- longform = ((mach_msg_type_t*)type)->msgt_longform;
- if (longform) {
- /* This must be aligned */
- if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
- (is_misaligned(type))) {
- saddr = ptr_align(saddr);
- continue;
- }
- name = type->msgtl_name;
- size = type->msgtl_size;
- number = type->msgtl_number;
- saddr += sizeof(mach_msg_type_long_t);
- } else {
- name = ((mach_msg_type_t*)type)->msgt_name;
- size = ((mach_msg_type_t*)type)->msgt_size;
- number = ((mach_msg_type_t*)type)->msgt_number;
- saddr += sizeof(mach_msg_type_t);
- }
- /* padding (ptrs and ports) ? */
- if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
- ((size >> 3) == sizeof(natural_t)))
- saddr = ptr_align(saddr);
- /* calculate length of data in bytes, rounding up */
- length = (((uint64_t) number * size) + 7) >> 3;
- is_port = MACH_MSG_TYPE_PORT_ANY(name);
- if (is_port) {
- mach_port_t *objects;
- mach_msg_type_number_t i;
- if (!is_inline && (length != 0)) {
- /* first allocate memory in the map */
- kr = vm_allocate(map, &addr, length, TRUE);
- if (kr != KERN_SUCCESS) {
- ipc_kmsg_clean_body(taddr, saddr);
- goto vm_copyout_failure;
- }
- }
- objects = (mach_port_t *)
- (is_inline ? saddr : * (vm_offset_t *) saddr);
- /* copyout port rights carried in the message */
- for (i = 0; i < number; i++) {
- ipc_object_t object =
- (ipc_object_t) objects[i];
- mr |= ipc_kmsg_copyout_object(space, object,
- name, &objects[i]);
- }
- }
- if (is_inline) {
- /* inline data sizes round up to int boundaries */
- ((mach_msg_type_t*)type)->msgt_deallocate = FALSE;
- saddr += (length + 3) &~ 3;
- } else {
- vm_offset_t data;
- if (sizeof(vm_offset_t) > sizeof(mach_msg_type_t))
- saddr = ptr_align(saddr);
- data = * (vm_offset_t *) saddr;
- /* copyout memory carried in the message */
- if (length == 0) {
- assert(data == 0);
- addr = 0;
- } else if (is_port) {
- /* copyout to memory allocated above */
- (void) copyoutmap(map, (char *) data,
- (char *) addr, length);
- kfree(data, length);
- } else {
- vm_map_copy_t copy = (vm_map_copy_t) data;
- kr = vm_map_copyout(map, &addr, copy);
- if (kr != KERN_SUCCESS) {
- vm_map_copy_discard(copy);
- vm_copyout_failure:
- addr = 0;
- if (longform)
- type->msgtl_size = 0;
- else
- ((mach_msg_type_t*)type)->msgt_size = 0;
- if (kr == KERN_RESOURCE_SHORTAGE)
- mr |= MACH_MSG_VM_KERNEL;
- else
- mr |= MACH_MSG_VM_SPACE;
- }
- }
- ((mach_msg_type_t*)type)->msgt_deallocate = TRUE;
- * (vm_offset_t *) saddr = addr;
- saddr += sizeof(vm_offset_t);
- }
- }
- return mr;
- }
- /*
- * Routine: ipc_kmsg_copyout
- * Purpose:
- * "Copy-out" port rights and out-of-line memory
- * in the message.
- * Conditions:
- * Nothing locked.
- * Returns:
- * MACH_MSG_SUCCESS Copied out all rights and memory.
- * MACH_RCV_INVALID_NOTIFY Bad notify port.
- * Rights and memory in the message are intact.
- * MACH_RCV_HEADER_ERROR + special bits
- * Rights and memory in the message are intact.
- * MACH_RCV_BODY_ERROR + special bits
- * The message header was successfully copied out.
- * As much of the body was handled as possible.
- */
- mach_msg_return_t
- ipc_kmsg_copyout(
- ipc_kmsg_t kmsg,
- ipc_space_t space,
- vm_map_t map,
- mach_port_t notify)
- {
- mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits;
- mach_msg_return_t mr;
- mr = ipc_kmsg_copyout_header(&kmsg->ikm_header, space, notify);
- if (mr != MACH_MSG_SUCCESS)
- return mr;
- if (mbits & MACH_MSGH_BITS_COMPLEX) {
- vm_offset_t saddr, eaddr;
- saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
- eaddr = (vm_offset_t) &kmsg->ikm_header +
- kmsg->ikm_header.msgh_size;
- mr = ipc_kmsg_copyout_body(saddr, eaddr, space, map);
- if (mr != MACH_MSG_SUCCESS)
- mr |= MACH_RCV_BODY_ERROR;
- }
- return mr;
- }
- /*
- * Routine: ipc_kmsg_copyout_pseudo
- * Purpose:
- * Does a pseudo-copyout of the message.
- * This is like a regular copyout, except
- * that the ports in the header are handled
- * as if they are in the body. They aren't reversed.
- *
- * The error codes are a combination of special bits.
- * The copyout proceeds despite errors.
- * Conditions:
- * Nothing locked.
- * Returns:
- * MACH_MSG_SUCCESS Successful copyout.
- * MACH_MSG_IPC_SPACE No room for port right in name space.
- * MACH_MSG_VM_SPACE No room for memory in address space.
- * MACH_MSG_IPC_KERNEL Resource shortage handling port right.
- * MACH_MSG_VM_KERNEL Resource shortage handling memory.
- */
- mach_msg_return_t
- ipc_kmsg_copyout_pseudo(
- ipc_kmsg_t kmsg,
- ipc_space_t space,
- vm_map_t map)
- {
- mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits;
- ipc_object_t dest = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
- ipc_object_t reply = (ipc_object_t) kmsg->ikm_header.msgh_local_port;
- mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits);
- mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits);
- mach_port_t dest_name, reply_name;
- mach_msg_return_t mr;
- assert(IO_VALID(dest));
- mr = (ipc_kmsg_copyout_object(space, dest, dest_type, &dest_name) |
- ipc_kmsg_copyout_object(space, reply, reply_type, &reply_name));
- kmsg->ikm_header.msgh_bits = mbits &~ MACH_MSGH_BITS_CIRCULAR;
- kmsg->ikm_header.msgh_remote_port = dest_name;
- kmsg->ikm_header.msgh_local_port = reply_name;
- if (mbits & MACH_MSGH_BITS_COMPLEX) {
- vm_offset_t saddr, eaddr;
- saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
- eaddr = (vm_offset_t) &kmsg->ikm_header +
- kmsg->ikm_header.msgh_size;
- mr |= ipc_kmsg_copyout_body(saddr, eaddr, space, map);
- }
- return mr;
- }
- /*
- * Routine: ipc_kmsg_copyout_dest
- * Purpose:
- * Copies out the destination port in the message.
- * Destroys all other rights and memory in the message.
- * Conditions:
- * Nothing locked.
- */
- void
- ipc_kmsg_copyout_dest(
- ipc_kmsg_t kmsg,
- ipc_space_t space)
- {
- mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits;
- ipc_object_t dest = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
- ipc_object_t reply = (ipc_object_t) kmsg->ikm_header.msgh_local_port;
- mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits);
- mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits);
- mach_port_t dest_name, reply_name;
-
- printk(KERN_ERR,"ipc_kmsg_copyout_dest\n");
- return -1;//BUG here -- assert fails
- assert(IO_VALID(dest));
- io_lock(dest);
- if (io_active(dest)) {
- ipc_object_copyout_dest(space, dest, dest_type, &dest_name);
- /* dest is unlocked */
- } else {
- io_release(dest);
- io_check_unlock(dest);
- dest_name = MACH_PORT_DEAD;
- }
- if (IO_VALID(reply)) {
- ipc_object_destroy(reply, reply_type);
- reply_name = MACH_PORT_NULL;
- } else
- reply_name = (mach_port_t) reply;
- kmsg->ikm_header.msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
- MACH_MSGH_BITS(reply_type, dest_type));
- kmsg->ikm_header.msgh_local_port = dest_name;
- kmsg->ikm_header.msgh_remote_port = reply_name;
- if (mbits & MACH_MSGH_BITS_COMPLEX) {
- vm_offset_t saddr, eaddr;
- saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
- eaddr = (vm_offset_t) &kmsg->ikm_header +
- kmsg->ikm_header.msgh_size;
- ipc_kmsg_clean_body(saddr, eaddr);
- }
- }
- #if MACH_KDB
- char *
- ipc_type_name(
- int type_name,
- boolean_t received)
- {
- switch (type_name) {
- case MACH_MSG_TYPE_BOOLEAN:
- return "boolean";
- case MACH_MSG_TYPE_INTEGER_16:
- return "short";
- case MACH_MSG_TYPE_INTEGER_32:
- return "int32";
- case MACH_MSG_TYPE_INTEGER_64:
- return "int64";
- case MACH_MSG_TYPE_CHAR:
- return "char";
- case MACH_MSG_TYPE_BYTE:
- return "byte";
- case MACH_MSG_TYPE_REAL:
- return "real";
- case MACH_MSG_TYPE_STRING:
- return "string";
- case MACH_MSG_TYPE_PORT_NAME:
- return "port_name";
- case MACH_MSG_TYPE_MOVE_RECEIVE:
- if (received) {
- return "port_receive";
- } else {
- return "move_receive";
- }
- case MACH_MSG_TYPE_MOVE_SEND:
- if (received) {
- return "port_send";
- } else {
- return "move_send";
- }
- case MACH_MSG_TYPE_MOVE_SEND_ONCE:
- if (received) {
- return "port_send_once";
- } else {
- return "move_send_once";
- }
- case MACH_MSG_TYPE_COPY_SEND:
- return "copy_send";
- case MACH_MSG_TYPE_MAKE_SEND:
- return "make_send";
- case MACH_MSG_TYPE_MAKE_SEND_ONCE:
- return "make_send_once";
- default:
- return (char *) 0;
- }
- }
- void
- ipc_print_type_name(
- int type_name)
- {
- char *name = ipc_type_name(type_name, TRUE);
- if (name) {
- printf("%s", name);
- } else {
- printf("type%d", type_name);
- }
- }
- /*
- * ipc_kmsg_print [ debug ]
- */
- void
- ipc_kmsg_print(ipc_kmsg_t kmsg)
- {
- db_printf("kmsg=0x%x\n", kmsg);
- db_printf("ikm_next=0x%x,prev=0x%x,size=%d,marequest=0x%x",
- kmsg->ikm_next,
- kmsg->ikm_prev,
- kmsg->ikm_size,
- kmsg->ikm_marequest);
- db_printf("\n");
- ipc_msg_print(&kmsg->ikm_header);
- }
- /*
- * ipc_msg_print [ debug ]
- */
- void
- ipc_msg_print(mach_msg_header_t *msgh)
- {
- vm_offset_t saddr, eaddr;
- db_printf("msgh_bits=0x%x: ", msgh->msgh_bits);
- if (msgh->msgh_bits & MACH_MSGH_BITS_COMPLEX) {
- db_printf("complex,");
- }
- if (msgh->msgh_bits & MACH_MSGH_BITS_CIRCULAR) {
- db_printf("circular,");
- }
- if (msgh->msgh_bits & MACH_MSGH_BITS_COMPLEX_PORTS) {
- db_printf("complex_ports,");
- }
- if (msgh->msgh_bits & MACH_MSGH_BITS_COMPLEX_DATA) {
- db_printf("complex_data,");
- }
- if (msgh->msgh_bits & MACH_MSGH_BITS_MIGRATED) {
- db_printf("migrated,");
- }
- if (msgh->msgh_bits & MACH_MSGH_BITS_UNUSED) {
- db_printf("unused=0x%x,",
- msgh->msgh_bits & MACH_MSGH_BITS_UNUSED);
- }
- db_printf("l=0x%x,r=0x%x\n",
- MACH_MSGH_BITS_LOCAL(msgh->msgh_bits),
- MACH_MSGH_BITS_REMOTE(msgh->msgh_bits));
- db_printf("msgh_id=%d,size=%d,seqno=%d,",
- msgh->msgh_id,
- msgh->msgh_size,
- msgh->msgh_seqno);
- if (msgh->msgh_remote_port) {
- db_printf("remote=0x%x(", msgh->msgh_remote_port);
- ipc_print_type_name(MACH_MSGH_BITS_REMOTE(msgh->msgh_bits));
- db_printf("),");
- } else {
- db_printf("remote=null,\n");
- }
- if (msgh->msgh_local_port) {
- db_printf("local=0x%x(", msgh->msgh_local_port);
- ipc_print_type_name(MACH_MSGH_BITS_LOCAL(msgh->msgh_bits));
- db_printf(")\n");
- } else {
- db_printf("local=null\n");
- }
- saddr = (vm_offset_t) (msgh + 1);
- eaddr = (vm_offset_t) msgh + msgh->msgh_size;
- while (saddr < eaddr) {
- mach_msg_type_long_t *type;
- mach_msg_type_name_t name;
- mach_msg_type_size_t size;
- mach_msg_type_number_t number;
- boolean_t is_inline, longform, dealloc, is_port;
- vm_size_t length;
- type = (mach_msg_type_long_t *) saddr;
- if (((eaddr - saddr) < sizeof(mach_msg_type_t)) ||
- ((longform = ((mach_msg_type_t*)type)->msgt_longform) &&
- ((eaddr - saddr) < sizeof(mach_msg_type_long_t)))) {
- db_printf("*** msg too small\n");
- return;
- }
- is_inline = ((mach_msg_type_t*)type)->msgt_inline;
- dealloc = ((mach_msg_type_t*)type)->msgt_deallocate;
- if (longform) {
- /* This must be aligned */
- if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
- (is_misaligned(type))) {
- saddr = ptr_align(saddr);
- continue;
- }
- name = type->msgtl_name;
- size = type->msgtl_size;
- number = type->msgtl_number;
- saddr += sizeof(mach_msg_type_long_t);
- } else {
- name = ((mach_msg_type_t*)type)->msgt_name;
- size = ((mach_msg_type_t*)type)->msgt_size;
- number = ((mach_msg_type_t*)type)->msgt_number;
- saddr += sizeof(mach_msg_type_t);
- }
- db_printf("-- type=");
- ipc_print_type_name(name);
- if (! is_inline) {
- db_printf(",ool");
- }
- if (dealloc) {
- db_printf(",dealloc");
- }
- if (longform) {
- db_printf(",longform");
- }
- db_printf(",size=%d,number=%d,addr=0x%x\n",
- size,
- number,
- saddr);
- is_port = MACH_MSG_TYPE_PORT_ANY(name);
- if ((is_port && (size != PORT_T_SIZE_IN_BITS)) ||
- (longform && ((type->msgtl_header.msgt_name != 0) ||
- (type->msgtl_header.msgt_size != 0) ||
- (type->msgtl_header.msgt_number != 0))) ||
- (((mach_msg_type_t*)type)->msgt_unused != 0) ||
- (dealloc && is_inline)) {
- db_printf("*** invalid type\n");
- return;
- }
- /* padding (ptrs and ports) ? */
- if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
- ((size >> 3) == sizeof(natural_t)))
- saddr = ptr_align(saddr);
- /* calculate length of data in bytes, rounding up */
- length = ((number * size) + 7) >> 3;
- if (is_inline) {
- vm_size_t amount;
- unsigned i, numwords;
- /* inline data sizes round up to int boundaries */
- amount = (length + 3) &~ 3;
- if ((eaddr - saddr) < amount) {
- db_printf("*** too small\n");
- return;
- }
- numwords = amount / sizeof(int);
- if (numwords > 8) {
- numwords = 8;
- }
- for (i = 0; i < numwords; i++) {
- db_printf("0x%x\n", ((int *) saddr)[i]);
- }
- if (numwords < amount / sizeof(int)) {
- db_printf("...\n");
- }
- saddr += amount;
- } else {
- if ((eaddr - saddr) < sizeof(vm_offset_t)) {
- db_printf("*** too small\n");
- return;
- }
- db_printf("0x%x\n", * (vm_offset_t *) saddr);
- saddr += sizeof(vm_offset_t);
- }
- }
- }
- #endif /* MACH_KDB */
|