Ignore:
File:
1 edited

Legend:

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

    r706b4de rcde999a  
    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)))
     
    154155 * @param olddata Saved data of the request.
    155156 *
    156  * @return Return EOK on success or a negative error code.
     157 * @return Return EOK on success or an error code.
    157158 *
    158159 */
     
    193194        spinlock_unlock(&answer->forget_lock);
    194195
    195         if ((native_t) IPC_GET_RETVAL(answer->data) == EHANGUP) {
     196        if ((int) IPC_GET_RETVAL(answer->data) == EHANGUP) {
    196197                phone_t *phone = answer->caller_phone;
    197198                mutex_lock(&phone->lock);
     
    238239static void process_answer(call_t *call)
    239240{
    240         if (((native_t) IPC_GET_RETVAL(call->data) == EHANGUP) &&
     241        if (((int) IPC_GET_RETVAL(call->data) == EHANGUP) &&
    241242            (call->flags & IPC_CALL_FORWARDED))
    242243                IPC_SET_RETVAL(call->data, EFORWARD);
     
    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 An 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}
     
    704728                return ENOENT;
    705729       
    706         if (ipc_phone_hangup(kobj->phone)) {
    707                 kobject_put(kobj);
    708                 return -1;
    709         }
    710        
     730        int rc = ipc_phone_hangup(kobj->phone);
    711731        kobject_put(kobj);
    712         return 0;
     732        return rc;
    713733}
    714734
     
    720740 *                 for explanation.
    721741 *
    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  *
     742 * @return An error code on error.
    727743 */
    728744sysarg_t sys_ipc_wait_for_call(ipc_data_t *calldata, uint32_t usec,
     
    743759        udebug_stoppable_end();
    744760#endif
    745        
    746         if (!call)
    747                 return 0;
    748        
     761
     762        if (!call) {
     763                ipc_data_t data = {};
     764                data.cap_handle = CAP_NIL;
     765                STRUCT_TO_USPACE(calldata, &data);
     766                return EOK;
     767        }
     768       
     769        call->data.flags = call->flags;
    749770        if (call->flags & IPC_CALL_NOTIF) {
    750771                /* Set in_phone_hash to the interrupt counter */
    751772                call->data.phone = (void *) call->priv;
    752773               
     774                call->data.cap_handle = CAP_NIL;
     775
    753776                STRUCT_TO_USPACE(calldata, &call->data);
     777                kobject_put(call->kobject);
    754778               
    755                 ipc_call_free(call);
    756                
    757                 return ((sysarg_t) call) | IPC_CALLID_NOTIFICATION;
     779                return EOK;
    758780        }
    759781       
     
    762784               
    763785                if (call->flags & IPC_CALL_DISCARD_ANSWER) {
    764                         ipc_call_free(call);
     786                        kobject_put(call->kobject);
    765787                        goto restart;
    766788                }
     789
     790                call->data.cap_handle = CAP_NIL;
    767791               
    768792                STRUCT_TO_USPACE(calldata, &call->data);
    769                 ipc_call_free(call);
     793                kobject_put(call->kobject);
    770794               
    771                 return ((sysarg_t) call) | IPC_CALLID_ANSWERED;
     795                return EOK;
    772796        }
    773797       
     
    775799                goto restart;
    776800       
    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;
     801        cap_handle_t handle;
     802        int rc = cap_alloc(TASK, &handle);
     803        if (rc != EOK) {
     804                goto error;
     805        }
     806       
     807        call->data.cap_handle = handle;
     808
     809        /*
     810         * Include phone hash of the caller in the request, copy the whole
     811         * call->data, not only call->data.args.
     812         */
     813        rc = STRUCT_TO_USPACE(calldata, &call->data);
     814        if (rc != EOK)
     815                goto error;
     816
     817        kobject_add_ref(call->kobject);
     818        cap_publish(TASK, handle, call->kobject);
     819        return EOK;
     820
     821error:
     822        if (handle >= 0)
     823                cap_free(TASK, handle);
     824
     825        /*
     826         * The callee will not receive this call and no one else has a chance to
     827         * answer it. Set the IPC_CALL_AUTO_REPLY flag and return the EPARTY
     828         * error code.
     829         */
     830        ipc_data_t saved_data;
     831        bool saved;
     832
     833        if (answer_need_old(call)) {
     834                memcpy(&saved_data, &call->data, sizeof(call->data));
     835                saved = true;
     836        } else
     837                saved = false;
     838
     839        IPC_SET_RETVAL(call->data, EPARTY);
     840        (void) answer_preprocess(call, saved ? &saved_data : NULL);
     841        call->flags |= IPC_CALL_AUTO_REPLY;
     842        ipc_answer(&TASK->answerbox, call);
     843
     844        return rc;
    800845}
    801846
     
    815860 * @param ucode   Uspace pointer to the top-half pseudocode.
    816861 *
    817  * @return IRQ kernel object capability
     862 * @param[out] uspace_handle  Uspace pointer to IRQ kernel object capability
     863 *
    818864 * @return EPERM
    819865 * @return Error code returned by ipc_irq_subscribe().
    820866 *
    821867 */
    822 sysarg_t sys_ipc_irq_subscribe(inr_t inr, sysarg_t imethod, irq_code_t *ucode)
     868sysarg_t sys_ipc_irq_subscribe(inr_t inr, sysarg_t imethod, irq_code_t *ucode,
     869        cap_handle_t *uspace_handle)
    823870{
    824871        if (!(perm_get(TASK) & PERM_IRQ_REG))
    825872                return EPERM;
    826873       
    827         return ipc_irq_subscribe(&TASK->answerbox, inr, imethod, ucode);
     874        return ipc_irq_subscribe(&TASK->answerbox, inr, imethod, ucode, uspace_handle);
    828875}
    829876
     
    846893}
    847894
    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)
     895/** Syscall connect to a task by ID
     896 *
     897 * @return Error code.
     898 *
     899 */
     900sysarg_t sys_ipc_connect_kbox(task_id_t *uspace_taskid, cap_handle_t *uspace_phone)
    856901{
    857902#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);
     903        task_id_t taskid;
     904        cap_handle_t phone;
     905       
     906        int rc = copy_from_uspace(&taskid, uspace_taskid, sizeof(task_id_t));
     907        if (rc == EOK) {
     908                rc = ipc_connect_kbox((task_id_t) taskid, &phone);
     909        }
     910       
     911        if (rc == EOK) {
     912                rc = copy_to_uspace(uspace_phone, &phone, sizeof(cap_handle_t));
     913                if (rc != EOK) {
     914                        // Clean up the phone on failure.
     915                        sys_ipc_hangup(phone);
     916                }
     917        }
     918       
     919        return (sysarg_t) rc;
    864920#else
    865921        return (sysarg_t) ENOTSUP;
     
    867923}
    868924
    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 
    889925/** @}
    890926 */
Note: See TracChangeset for help on using the changeset viewer.