Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • kernel/generic/src/ipc/sysipc.c

    r706b4de r0016674  
    5353#include <print.h>
    5454#include <macros.h>
     55#include <cap/cap.h>
    5556
    5657#define STRUCT_TO_USPACE(dst, src)  copy_to_uspace((dst), (src), sizeof(*(src)))
     
    286287#endif
    287288
    288                 ipc_call_hold(call);
     289                kobject_add_ref(call->kobject);
    289290                rc = ipc_call_sync(kobj->phone, call);
    290291                spinlock_lock(&call->forget_lock);
    291292                bool forgotten = call->forget;
    292293                spinlock_unlock(&call->forget_lock);
    293                 ipc_call_release(call);
     294                kobject_put(call->kobject);
    294295
    295296#ifdef CONFIG_UDEBUG
     
    306307                                 * deallocation.
    307308                                 */
    308                                 ipc_call_free(call);
     309                                kobject_put(call->kobject);
    309310                        } else {
    310311                                /*
     
    323324       
    324325        memcpy(data->args, call->data.args, sizeof(data->args));
    325         ipc_call_free(call);
     326        kobject_put(call->kobject);
    326327        kobject_put(kobj);
    327328       
     
    347348/** Make a fast asynchronous call over IPC.
    348349 *
    349  * This function can only handle four arguments of payload, but is faster than
     350 * This function can only handle three arguments of payload, but is faster than
    350351 * the generic function sys_ipc_call_async_slow().
    351352 *
     
    355356 * @param arg2     Service-defined payload argument.
    356357 * @param arg3     Service-defined payload argument.
    357  * @param arg4     Service-defined payload argument.
    358  *
    359  * @return Call hash on success.
    360  * @return IPC_CALLRET_FATAL in case of a fatal error.
     358 * @param label    User-defined label.
     359 *
     360 * @return EOK on success.
     361 * @return Negative error code on error.
    361362 *
    362363 */
    363364sysarg_t sys_ipc_call_async_fast(sysarg_t handle, sysarg_t imethod,
    364     sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t arg4)
     365    sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t label)
    365366{
    366367        kobject_t *kobj = kobject_get(TASK, handle, KOBJECT_TYPE_PHONE);
    367368        if (!kobj)
    368                 return IPC_CALLRET_FATAL;
     369                return ENOENT;
    369370       
    370371        if (check_call_limit(kobj->phone)) {
    371372                kobject_put(kobj);
    372                 return IPC_CALLRET_FATAL;
     373                return ELIMIT;
    373374        }
    374375       
     
    378379        IPC_SET_ARG2(call->data, arg2);
    379380        IPC_SET_ARG3(call->data, arg3);
    380         IPC_SET_ARG4(call->data, arg4);
    381381       
    382382        /*
     
    385385         */
    386386        IPC_SET_ARG5(call->data, 0);
     387
     388        /* Set the user-defined label */
     389        call->data.label = label;
    387390       
    388391        int res = request_preprocess(call, kobj->phone);
     
    394397       
    395398        kobject_put(kobj);
    396         return (sysarg_t) call;
     399        return EOK;
    397400}
    398401
     
    401404 * @param handle  Phone capability for the call.
    402405 * @param data    Userspace address of call data with the request.
     406 * @param label   User-defined label.
    403407 *
    404408 * @return See sys_ipc_call_async_fast().
    405409 *
    406410 */
    407 sysarg_t sys_ipc_call_async_slow(sysarg_t handle, ipc_data_t *data)
     411sysarg_t sys_ipc_call_async_slow(sysarg_t handle, ipc_data_t *data,
     412    sysarg_t label)
    408413{
    409414        kobject_t *kobj = kobject_get(TASK, handle, KOBJECT_TYPE_PHONE);
    410415        if (!kobj)
    411                 return IPC_CALLRET_FATAL;
     416                return ENOENT;
    412417
    413418        if (check_call_limit(kobj->phone)) {
    414419                kobject_put(kobj);
    415                 return IPC_CALLRET_FATAL;
     420                return ELIMIT;
    416421        }
    417422
     
    420425            sizeof(call->data.args));
    421426        if (rc != 0) {
    422                 ipc_call_free(call);
     427                kobject_put(call->kobject);
    423428                kobject_put(kobj);
    424429                return (sysarg_t) rc;
    425430        }
     431
     432        /* Set the user-defined label */
     433        call->data.label = label;
    426434       
    427435        int res = request_preprocess(call, kobj->phone);
     
    433441       
    434442        kobject_put(kobj);
    435         return (sysarg_t) call;
     443        return EOK;
    436444}
    437445
     
    440448 * Common code for both the fast and the slow version.
    441449 *
    442  * @param callid   Hash of the call to forward.
    443  * @param handle   Phone capability to use for forwarding.
     450 * @param chandle  Call handle of the forwarded call.
     451 * @param phandle  Phone handle to use for forwarding.
    444452 * @param imethod  New interface and method to use for the forwarded call.
    445453 * @param arg1     New value of the first argument for the forwarded call.
     
    458466 *
    459467 */
    460 static sysarg_t sys_ipc_forward_common(sysarg_t callid, sysarg_t handle,
     468static sysarg_t sys_ipc_forward_common(sysarg_t chandle, sysarg_t phandle,
    461469    sysarg_t imethod, sysarg_t arg1, sysarg_t arg2, sysarg_t arg3,
    462470    sysarg_t arg4, sysarg_t arg5, unsigned int mode, bool slow)
    463471{
    464         call_t *call = get_call(callid);
    465         if (!call)
     472        kobject_t *ckobj = cap_unpublish(TASK, chandle, KOBJECT_TYPE_CALL);
     473        if (!ckobj)
    466474                return ENOENT;
    467475       
     476        call_t *call = ckobj->call;
     477
    468478        ipc_data_t old;
    469479        bool need_old = answer_need_old(call);
     
    474484        int rc;
    475485
    476         kobject_t *kobj = kobject_get(TASK, handle, KOBJECT_TYPE_PHONE);
    477         if (!kobj) {
     486        kobject_t *pkobj = kobject_get(TASK, phandle, KOBJECT_TYPE_PHONE);
     487        if (!pkobj) {
    478488                rc = ENOENT;
    479489                goto error;
     
    521531        }
    522532       
    523         rc = ipc_forward(call, kobj->phone, &TASK->answerbox, mode);
     533        rc = ipc_forward(call, pkobj->phone, &TASK->answerbox, mode);
    524534        if (rc != EOK) {
    525535                after_forward = true;
     
    527537        }
    528538
    529         kobject_put(kobj);
     539        cap_free(TASK, chandle);
     540        kobject_put(ckobj);
     541        kobject_put(pkobj);
    530542        return EOK;
    531543
     
    538550                ipc_answer(&TASK->answerbox, call);
    539551
    540         if (kobj)
    541                 kobject_put(kobj);
     552        /* Republish the capability so that the call does not get lost. */
     553        cap_publish(TASK, chandle, ckobj);
     554
     555        if (pkobj)
     556                kobject_put(pkobj);
    542557        return rc;
    543558}
     
    552567 * arguments are not set and these values are ignored.
    553568 *
    554  * @param callid   Hash of the call to forward.
    555  * @param handle   Phone handle to use for forwarding.
     569 * @param chandle  Call handle of the call to forward.
     570 * @param phandle  Phone handle to use for forwarding.
    556571 * @param imethod  New interface and method to use for the forwarded call.
    557572 * @param arg1     New value of the first argument for the forwarded call.
     
    562577 *
    563578 */
    564 sysarg_t sys_ipc_forward_fast(sysarg_t callid, sysarg_t handle,
     579sysarg_t sys_ipc_forward_fast(sysarg_t chandle, sysarg_t phandle,
    565580    sysarg_t imethod, sysarg_t arg1, sysarg_t arg2, unsigned int mode)
    566581{
    567         return sys_ipc_forward_common(callid, handle, imethod, arg1, arg2, 0, 0,
    568             0, mode, false);
     582        return sys_ipc_forward_common(chandle, phandle, imethod, arg1, arg2, 0,
     583            0, 0, mode, false);
    569584}
    570585
     
    578593 * and arg5, respectively, to ARG3, ARG4 and ARG5, respectively.
    579594 *
    580  * @param callid  Hash of the call to forward.
    581  * @param handle  Phone handle to use for forwarding.
    582  * @param data    Userspace address of the new IPC data.
    583  * @param mode    Flags that specify mode of the forward operation.
     595 * @param chandle  Call handle of the call to forward.
     596 * @param phandle  Phone handle to use for forwarding.
     597 * @param data     Userspace address of the new IPC data.
     598 * @param mode     Flags that specify mode of the forward operation.
    584599 *
    585600 * @return 0 on succes, otherwise an error code.
    586601 *
    587602 */
    588 sysarg_t sys_ipc_forward_slow(sysarg_t callid, sysarg_t handle,
     603sysarg_t sys_ipc_forward_slow(sysarg_t chandle, sysarg_t phandle,
    589604    ipc_data_t *data, unsigned int mode)
    590605{
     
    595610                return (sysarg_t) rc;
    596611       
    597         return sys_ipc_forward_common(callid, handle,
     612        return sys_ipc_forward_common(chandle, phandle,
    598613            IPC_GET_IMETHOD(newdata), IPC_GET_ARG1(newdata),
    599614            IPC_GET_ARG2(newdata), IPC_GET_ARG3(newdata),
    600             IPC_GET_ARG4(newdata), IPC_GET_ARG5(newdata), mode, true); 
     615            IPC_GET_ARG4(newdata), IPC_GET_ARG5(newdata), mode, true);
    601616}
    602617
     
    606621 * than the generic sys_ipc_answer().
    607622 *
    608  * @param callid Hash of the call to be answered.
    609  * @param retval Return value of the answer.
    610  * @param arg1   Service-defined return value.
    611  * @param arg2   Service-defined return value.
    612  * @param arg3   Service-defined return value.
    613  * @param arg4   Service-defined return value.
     623 * @param chandle  Call handle to be answered.
     624 * @param retval   Return value of the answer.
     625 * @param arg1     Service-defined return value.
     626 * @param arg2     Service-defined return value.
     627 * @param arg3     Service-defined return value.
     628 * @param arg4     Service-defined return value.
    614629 *
    615630 * @return 0 on success, otherwise an error code.
    616631 *
    617632 */
    618 sysarg_t sys_ipc_answer_fast(sysarg_t callid, sysarg_t retval,
    619     sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t arg4)
    620 {
    621         /* Do not answer notification callids */
    622         if (callid & IPC_CALLID_NOTIFICATION)
    623                 return 0;
    624        
    625         call_t *call = get_call(callid);
    626         if (!call)
     633sysarg_t sys_ipc_answer_fast(sysarg_t chandle, sysarg_t retval, sysarg_t arg1,
     634    sysarg_t arg2, sysarg_t arg3, sysarg_t arg4)
     635{
     636        kobject_t *kobj = cap_unpublish(TASK, chandle, KOBJECT_TYPE_CALL);
     637        if (!kobj)
    627638                return ENOENT;
    628639       
     640        call_t *call = kobj->call;
     641
    629642        ipc_data_t saved_data;
    630643        bool saved;
     
    650663       
    651664        ipc_answer(&TASK->answerbox, call);
     665
     666        kobject_put(kobj);
     667        cap_free(TASK, chandle);
     668
    652669        return rc;
    653670}
     
    655672/** Answer an IPC call.
    656673 *
    657  * @param callid Hash of the call to be answered.
    658  * @param data   Userspace address of call data with the answer.
     674 * @param chandle Call handle to be answered.
     675 * @param data    Userspace address of call data with the answer.
    659676 *
    660677 * @return 0 on success, otherwise an error code.
    661678 *
    662679 */
    663 sysarg_t sys_ipc_answer_slow(sysarg_t callid, ipc_data_t *data)
    664 {
    665         /* Do not answer notification callids */
    666         if (callid & IPC_CALLID_NOTIFICATION)
    667                 return 0;
    668        
    669         call_t *call = get_call(callid);
    670         if (!call)
     680sysarg_t sys_ipc_answer_slow(sysarg_t chandle, ipc_data_t *data)
     681{
     682        kobject_t *kobj = cap_unpublish(TASK, chandle, KOBJECT_TYPE_CALL);
     683        if (!kobj)
    671684                return ENOENT;
    672685       
     686        call_t *call = kobj->call;
     687
    673688        ipc_data_t saved_data;
    674689        bool saved;
     
    682697        int rc = copy_from_uspace(&call->data.args, &data->args,
    683698            sizeof(call->data.args));
    684         if (rc != 0)
     699        if (rc != 0) {
     700                /*
     701                 * Republish the capability so that the call does not get lost.
     702                 */
     703                cap_publish(TASK, chandle, kobj);
    685704                return rc;
     705        }
    686706       
    687707        rc = answer_preprocess(call, saved ? &saved_data : NULL);
    688708       
    689709        ipc_answer(&TASK->answerbox, call);
     710
     711        kobject_put(kobj);
     712        cap_free(TASK, chandle);
     713
    690714        return rc;
    691715}
     
    720744 *                 for explanation.
    721745 *
    722  * @return Hash of the call.
    723  *         If IPC_CALLID_NOTIFICATION bit is set in the hash, the
    724  *         call is a notification. IPC_CALLID_ANSWERED denotes an
    725  *         answer.
    726  *
     746 * @return Negative error code on error.
    727747 */
    728748sysarg_t sys_ipc_wait_for_call(ipc_data_t *calldata, uint32_t usec,
     
    743763        udebug_stoppable_end();
    744764#endif
    745        
    746         if (!call)
    747                 return 0;
     765
     766        if (!call) {
     767                ipc_data_t data = {0};
     768                data.cap_handle = CAP_NIL;
     769                STRUCT_TO_USPACE(calldata, &data);
     770                return EOK;
     771        }
    748772       
    749773        if (call->flags & IPC_CALL_NOTIF) {
     
    751775                call->data.phone = (void *) call->priv;
    752776               
     777                call->data.flags = IPC_CALL_NOTIF;
     778                call->data.cap_handle = CAP_NIL;
     779
    753780                STRUCT_TO_USPACE(calldata, &call->data);
     781                kobject_put(call->kobject);
    754782               
    755                 ipc_call_free(call);
    756                
    757                 return ((sysarg_t) call) | IPC_CALLID_NOTIFICATION;
     783                return EOK;
    758784        }
    759785       
     
    762788               
    763789                if (call->flags & IPC_CALL_DISCARD_ANSWER) {
    764                         ipc_call_free(call);
     790                        kobject_put(call->kobject);
    765791                        goto restart;
    766792                }
     793
     794                call->data.flags = IPC_CALL_ANSWERED;
     795                call->data.cap_handle = CAP_NIL;
    767796               
    768797                STRUCT_TO_USPACE(calldata, &call->data);
    769                 ipc_call_free(call);
     798                kobject_put(call->kobject);
    770799               
    771                 return ((sysarg_t) call) | IPC_CALLID_ANSWERED;
     800                return EOK;
    772801        }
    773802       
     
    775804                goto restart;
    776805       
    777         /* Include phone address('id') of the caller in the request,
    778          * copy whole call->data, not only call->data.args */
    779         if (STRUCT_TO_USPACE(calldata, &call->data)) {
    780                 /*
    781                  * The callee will not receive this call and no one else has
    782                  * a chance to answer it. Reply with the EPARTY error code.
    783                  */
    784                 ipc_data_t saved_data;
    785                 bool saved;
    786                
    787                 if (answer_need_old(call)) {
    788                         memcpy(&saved_data, &call->data, sizeof(call->data));
    789                         saved = true;
    790                 } else
    791                         saved = false;
    792                
    793                 IPC_SET_RETVAL(call->data, EPARTY);
    794                 (void) answer_preprocess(call, saved ? &saved_data : NULL);
    795                 ipc_answer(&TASK->answerbox, call);
    796                 return 0;
    797         }
    798        
    799         return (sysarg_t) call;
     806        int rc;
     807        cap_handle_t handle = cap_alloc(TASK);
     808        if (handle < 0) {
     809                rc = handle;
     810                goto error;
     811        }
     812       
     813        call->data.cap_handle = handle;
     814
     815        /*
     816         * Include phone hash of the caller in the request, copy the whole
     817         * call->data, not only call->data.args.
     818         */
     819        rc = STRUCT_TO_USPACE(calldata, &call->data);
     820        if (rc != EOK)
     821                goto error;
     822
     823        kobject_add_ref(call->kobject);
     824        cap_publish(TASK, handle, call->kobject);
     825        return EOK;
     826
     827error:
     828        if (handle >= 0)
     829                cap_free(TASK, handle);
     830
     831        /*
     832         * The callee will not receive this call and no one else has a chance to
     833         * answer it. Reply with the EPARTY error code.
     834         */
     835        ipc_data_t saved_data;
     836        bool saved;
     837
     838        if (answer_need_old(call)) {
     839                memcpy(&saved_data, &call->data, sizeof(call->data));
     840                saved = true;
     841        } else
     842                saved = false;
     843
     844        IPC_SET_RETVAL(call->data, EPARTY);
     845        (void) answer_preprocess(call, saved ? &saved_data : NULL);
     846        ipc_answer(&TASK->answerbox, call);
     847
     848        return rc;
    800849}
    801850
     
    815864 * @param ucode   Uspace pointer to the top-half pseudocode.
    816865 *
    817  * @return IRQ kernel object capability
     866 * @param[out] uspace_handle  Uspace pointer to IRQ kernel object capability
     867 *
    818868 * @return EPERM
    819869 * @return Error code returned by ipc_irq_subscribe().
    820870 *
    821871 */
    822 sysarg_t sys_ipc_irq_subscribe(inr_t inr, sysarg_t imethod, irq_code_t *ucode)
     872sysarg_t sys_ipc_irq_subscribe(inr_t inr, sysarg_t imethod, irq_code_t *ucode,
     873        cap_handle_t *uspace_handle)
    823874{
    824875        if (!(perm_get(TASK) & PERM_IRQ_REG))
    825876                return EPERM;
    826877       
    827         return ipc_irq_subscribe(&TASK->answerbox, inr, imethod, ucode);
     878        return ipc_irq_subscribe(&TASK->answerbox, inr, imethod, ucode, uspace_handle);
    828879}
    829880
     
    846897}
    847898
    848 #ifdef __32_BITS__
    849 
    850 /** Syscall connect to a task by ID (32 bits)
    851  *
    852  * @return Phone id on success, or negative error code.
    853  *
    854  */
    855 sysarg_t sys_ipc_connect_kbox(sysarg64_t *uspace_taskid)
     899/** Syscall connect to a task by ID
     900 *
     901 * @return Error code.
     902 *
     903 */
     904sysarg_t sys_ipc_connect_kbox(task_id_t *uspace_taskid, cap_handle_t *uspace_phone)
    856905{
    857906#ifdef CONFIG_UDEBUG
    858         sysarg64_t taskid;
    859         int rc = copy_from_uspace(&taskid, uspace_taskid, sizeof(sysarg64_t));
    860         if (rc != 0)
    861                 return (sysarg_t) rc;
    862        
    863         return ipc_connect_kbox((task_id_t) taskid);
     907        task_id_t taskid;
     908        cap_handle_t phone;
     909       
     910        int rc = copy_from_uspace(&taskid, uspace_taskid, sizeof(task_id_t));
     911        if (rc == EOK) {
     912                rc = ipc_connect_kbox((task_id_t) taskid, &phone);
     913        }
     914       
     915        if (rc == EOK) {
     916                rc = copy_to_uspace(uspace_phone, &phone, sizeof(cap_handle_t));
     917                if (rc != EOK) {
     918                        // Clean up the phone on failure.
     919                        sys_ipc_hangup(phone);
     920                }
     921        }
     922       
     923        return (sysarg_t) rc;
    864924#else
    865925        return (sysarg_t) ENOTSUP;
     
    867927}
    868928
    869 #endif  /* __32_BITS__ */
    870 
    871 #ifdef __64_BITS__
    872 
    873 /** Syscall connect to a task by ID (64 bits)
    874  *
    875  * @return Phone id on success, or negative error code.
    876  *
    877  */
    878 sysarg_t sys_ipc_connect_kbox(sysarg_t taskid)
    879 {
    880 #ifdef CONFIG_UDEBUG
    881         return ipc_connect_kbox((task_id_t) taskid);
    882 #else
    883         return (sysarg_t) ENOTSUP;
    884 #endif
    885 }
    886 
    887 #endif  /* __64_BITS__ */
    888 
    889929/** @}
    890930 */
Note: See TracChangeset for help on using the changeset viewer.