Changeset 01c3bb4 in mainline for kernel/generic/src/ipc/sysipc.c


Ignore:
Timestamp:
2017-11-25T15:43:25Z (6 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
ce4a21a0
Parents:
98cb5e0d
Message:

Convert call-handling syscalls to capabilities

This commit modifies the behavior of sys_ipc_wait_for_call() to return a
capability handle for requests. This capability handle can be used
either by sys_ipc_answer*() to answer the call or by sys_ipc_forward*()
to forward it further along. Answering or forwarding the call results in
destruction of the respective capability. For requests and
notifications, sys_ipc_wait_for_call() returns CAP_NIL and sets call
flags accordingly.

File:
1 edited

Legend:

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

    r98cb5e0d r01c3bb4  
    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)))
     
    447448 * Common code for both the fast and the slow version.
    448449 *
    449  * @param callid   Hash of the call to forward.
    450  * @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.
    451452 * @param imethod  New interface and method to use for the forwarded call.
    452453 * @param arg1     New value of the first argument for the forwarded call.
     
    465466 *
    466467 */
    467 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,
    468469    sysarg_t imethod, sysarg_t arg1, sysarg_t arg2, sysarg_t arg3,
    469470    sysarg_t arg4, sysarg_t arg5, unsigned int mode, bool slow)
    470471{
    471         call_t *call = get_call(callid);
    472         if (!call)
     472        kobject_t *ckobj = cap_unpublish(TASK, chandle, KOBJECT_TYPE_CALL);
     473        if (!ckobj)
    473474                return ENOENT;
    474475       
     476        call_t *call = ckobj->call;
     477
    475478        ipc_data_t old;
    476479        bool need_old = answer_need_old(call);
     
    481484        int rc;
    482485
    483         kobject_t *kobj = kobject_get(TASK, handle, KOBJECT_TYPE_PHONE);
    484         if (!kobj) {
     486        kobject_t *pkobj = kobject_get(TASK, phandle, KOBJECT_TYPE_PHONE);
     487        if (!pkobj) {
    485488                rc = ENOENT;
    486489                goto error;
     
    528531        }
    529532       
    530         rc = ipc_forward(call, kobj->phone, &TASK->answerbox, mode);
     533        rc = ipc_forward(call, pkobj->phone, &TASK->answerbox, mode);
    531534        if (rc != EOK) {
    532535                after_forward = true;
     
    534537        }
    535538
    536         kobject_put(kobj);
     539        cap_free(TASK, chandle);
     540        kobject_put(ckobj);
     541        kobject_put(pkobj);
    537542        return EOK;
    538543
     
    545550                ipc_answer(&TASK->answerbox, call);
    546551
    547         if (kobj)
    548                 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);
    549557        return rc;
    550558}
     
    559567 * arguments are not set and these values are ignored.
    560568 *
    561  * @param callid   Hash of the call to forward.
    562  * @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.
    563571 * @param imethod  New interface and method to use for the forwarded call.
    564572 * @param arg1     New value of the first argument for the forwarded call.
     
    569577 *
    570578 */
    571 sysarg_t sys_ipc_forward_fast(sysarg_t callid, sysarg_t handle,
     579sysarg_t sys_ipc_forward_fast(sysarg_t chandle, sysarg_t phandle,
    572580    sysarg_t imethod, sysarg_t arg1, sysarg_t arg2, unsigned int mode)
    573581{
    574         return sys_ipc_forward_common(callid, handle, imethod, arg1, arg2, 0, 0,
    575             0, mode, false);
     582        return sys_ipc_forward_common(chandle, phandle, imethod, arg1, arg2, 0,
     583            0, 0, mode, false);
    576584}
    577585
     
    585593 * and arg5, respectively, to ARG3, ARG4 and ARG5, respectively.
    586594 *
    587  * @param callid  Hash of the call to forward.
    588  * @param handle  Phone handle to use for forwarding.
    589  * @param data    Userspace address of the new IPC data.
    590  * @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.
    591599 *
    592600 * @return 0 on succes, otherwise an error code.
    593601 *
    594602 */
    595 sysarg_t sys_ipc_forward_slow(sysarg_t callid, sysarg_t handle,
     603sysarg_t sys_ipc_forward_slow(sysarg_t chandle, sysarg_t phandle,
    596604    ipc_data_t *data, unsigned int mode)
    597605{
     
    602610                return (sysarg_t) rc;
    603611       
    604         return sys_ipc_forward_common(callid, handle,
     612        return sys_ipc_forward_common(chandle, phandle,
    605613            IPC_GET_IMETHOD(newdata), IPC_GET_ARG1(newdata),
    606614            IPC_GET_ARG2(newdata), IPC_GET_ARG3(newdata),
    607             IPC_GET_ARG4(newdata), IPC_GET_ARG5(newdata), mode, true); 
     615            IPC_GET_ARG4(newdata), IPC_GET_ARG5(newdata), mode, true);
    608616}
    609617
     
    613621 * than the generic sys_ipc_answer().
    614622 *
    615  * @param callid Hash of the call to be answered.
    616  * @param retval Return value of the answer.
    617  * @param arg1   Service-defined return value.
    618  * @param arg2   Service-defined return value.
    619  * @param arg3   Service-defined return value.
    620  * @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.
    621629 *
    622630 * @return 0 on success, otherwise an error code.
    623631 *
    624632 */
    625 sysarg_t sys_ipc_answer_fast(sysarg_t callid, sysarg_t retval,
    626     sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t arg4)
    627 {
    628         /* Do not answer notification callids */
    629         if (callid & IPC_CALLID_NOTIFICATION)
    630                 return 0;
    631        
    632         call_t *call = get_call(callid);
    633         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)
    634638                return ENOENT;
    635639       
     640        call_t *call = kobj->call;
     641
    636642        ipc_data_t saved_data;
    637643        bool saved;
     
    657663       
    658664        ipc_answer(&TASK->answerbox, call);
     665
     666        kobject_put(kobj);
     667        cap_free(TASK, chandle);
     668
    659669        return rc;
    660670}
     
    662672/** Answer an IPC call.
    663673 *
    664  * @param callid Hash of the call to be answered.
    665  * @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.
    666676 *
    667677 * @return 0 on success, otherwise an error code.
    668678 *
    669679 */
    670 sysarg_t sys_ipc_answer_slow(sysarg_t callid, ipc_data_t *data)
    671 {
    672         /* Do not answer notification callids */
    673         if (callid & IPC_CALLID_NOTIFICATION)
    674                 return 0;
    675        
    676         call_t *call = get_call(callid);
    677         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)
    678684                return ENOENT;
    679685       
     686        call_t *call = kobj->call;
     687
    680688        ipc_data_t saved_data;
    681689        bool saved;
     
    689697        int rc = copy_from_uspace(&call->data.args, &data->args,
    690698            sizeof(call->data.args));
    691         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);
    692704                return rc;
     705        }
    693706       
    694707        rc = answer_preprocess(call, saved ? &saved_data : NULL);
    695708       
    696709        ipc_answer(&TASK->answerbox, call);
     710
     711        kobject_put(kobj);
     712        cap_free(TASK, chandle);
     713
    697714        return rc;
    698715}
     
    727744 *                 for explanation.
    728745 *
    729  * @return Hash of the call.
     746 * @return Capability handle of the received request.
     747 * @return CAP_NIL for answers, notifications and when there is no call.
     748 * @return Negative error code on error.
    730749 */
    731750sysarg_t sys_ipc_wait_for_call(ipc_data_t *calldata, uint32_t usec,
     
    746765        udebug_stoppable_end();
    747766#endif
    748        
    749         if (!call)
    750                 return 0;
     767
     768        if (!call) {
     769                STRUCT_TO_USPACE(calldata, &(ipc_data_t){});
     770                return CAP_NIL;
     771        }
    751772       
    752773        if (call->flags & IPC_CALL_NOTIF) {
     
    759780                kobject_put(call->kobject);
    760781               
    761                 return (sysarg_t) call;
     782                return CAP_NIL;
    762783        }
    763784       
     
    775796                kobject_put(call->kobject);
    776797               
    777                 return (sysarg_t) call;
     798                return CAP_NIL;
    778799        }
    779800       
     
    781802                goto restart;
    782803       
    783         /* Include phone address('id') of the caller in the request,
    784          * copy whole call->data, not only call->data.args */
    785         if (STRUCT_TO_USPACE(calldata, &call->data)) {
    786                 /*
    787                  * The callee will not receive this call and no one else has
    788                  * a chance to answer it. Reply with the EPARTY error code.
    789                  */
    790                 ipc_data_t saved_data;
    791                 bool saved;
    792                
    793                 if (answer_need_old(call)) {
    794                         memcpy(&saved_data, &call->data, sizeof(call->data));
    795                         saved = true;
    796                 } else
    797                         saved = false;
    798                
    799                 IPC_SET_RETVAL(call->data, EPARTY);
    800                 (void) answer_preprocess(call, saved ? &saved_data : NULL);
    801                 ipc_answer(&TASK->answerbox, call);
    802                 return 0;
    803         }
    804        
    805         return (sysarg_t) call;
     804        int rc;
     805        cap_handle_t handle = cap_alloc(TASK);
     806        if (handle < 0) {
     807                rc = handle;
     808                goto error;
     809        }
     810       
     811        /*
     812         * Include phone hash of the caller in the request, copy the whole
     813         * call->data, not only call->data.args.
     814         */
     815        rc = STRUCT_TO_USPACE(calldata, &call->data);
     816        if (rc != EOK)
     817                goto error;
     818
     819        kobject_add_ref(call->kobject);
     820        cap_publish(TASK, handle, call->kobject);
     821        return handle;
     822
     823error:
     824        if (handle >= 0)
     825                cap_free(TASK, handle);
     826
     827        /*
     828         * The callee will not receive this call and no one else has a chance to
     829         * answer it. Reply with the EPARTY error code.
     830         */
     831        ipc_data_t saved_data;
     832        bool saved;
     833
     834        if (answer_need_old(call)) {
     835                memcpy(&saved_data, &call->data, sizeof(call->data));
     836                saved = true;
     837        } else
     838                saved = false;
     839
     840        IPC_SET_RETVAL(call->data, EPARTY);
     841        (void) answer_preprocess(call, saved ? &saved_data : NULL);
     842        ipc_answer(&TASK->answerbox, call);
     843
     844        return rc;
    806845}
    807846
Note: See TracChangeset for help on using the changeset viewer.