Changes in / [983cabe8:3ffd4c3] in mainline


Ignore:
Files:
13 deleted
13 edited

Legend:

Unmodified
Added
Removed
  • abi/include/ipc/ipc.h

    r983cabe8 r3ffd4c3  
    5757#define IPC_CALL_FORWARDED  (1 << 2)
    5858
     59/** Identify connect_me_to answer */
     60#define IPC_CALL_CONN_ME_TO  (1 << 3)
     61
    5962/** Interrupt notification */
    60 #define IPC_CALL_NOTIF  (1 << 3)
     63#define IPC_CALL_NOTIF  (1 << 4)
    6164
    6265
  • kernel/Makefile

    r983cabe8 r3ffd4c3  
    257257        generic/src/ipc/ipc.c \
    258258        generic/src/ipc/sysipc.c \
    259         generic/src/ipc/sysipc_ops.c \
    260         generic/src/ipc/ops/clnestab.c \
    261         generic/src/ipc/ops/conctmeto.c \
    262         generic/src/ipc/ops/concttome.c \
    263         generic/src/ipc/ops/connclone.c \
    264         generic/src/ipc/ops/dataread.c \
    265         generic/src/ipc/ops/datawrite.c \
    266         generic/src/ipc/ops/debug.c \
    267         generic/src/ipc/ops/sharein.c \
    268         generic/src/ipc/ops/shareout.c \
    269         generic/src/ipc/ops/stchngath.c \
    270259        generic/src/ipc/ipcrsc.c \
    271260        generic/src/ipc/irq.c \
  • kernel/generic/include/config.h

    r983cabe8 r3ffd4c3  
    4747#define CONFIG_INIT_TASKS        32
    4848#define CONFIG_TASK_NAME_BUFLEN  32
    49 
    50 /**
    51  * Maximum buffer size allowed for IPC_M_DATA_WRITE and IPC_M_DATA_READ
    52  * requests.
    53  */
    54 #define DATA_XFER_LIMIT  (64 * 1024)
    5549
    5650#ifndef __ASM__
  • kernel/generic/include/ipc/ipc.h

    r983cabe8 r3ffd4c3  
    7272typedef struct answerbox {
    7373        IRQ_SPINLOCK_DECLARE(lock);
    74 
    75         /** Answerbox is active until it enters cleanup. */
    76         bool active;
    7774       
    7875        struct task *task;
     
    109106
    110107typedef struct {
    111         /**
    112          * Task link.
    113          * Valid only when the call is not forgotten.
    114          * Protected by the task's active_calls_lock.
    115          */
    116         link_t ta_link;
    117 
    118         /** Answerbox link. */
    119         link_t ab_link;
     108        link_t link;
    120109       
    121110        unsigned int flags;
    122 
    123         /** Protects the forget member. */
    124         SPINLOCK_DECLARE(forget_lock);
    125 
    126         /**
    127          * True if the caller 'forgot' this call and donated it to the callee.
    128          * Forgotten calls are discarded upon answering (the answer is not
    129          * delivered) and answered calls cannot be forgotten. Forgotten calls
    130          * also do not figure on the task's active call list.
    131          *
    132          * We keep this separate from the flags so that it is not necessary
    133          * to take a lock when accessing them.
    134          */
    135         bool forget;
    136 
    137         /** True if the call is in the active list. */
    138         bool active;
    139111       
    140         /**
    141          * Identification of the caller.
    142          * Valid only when the call is not forgotten.
    143          */
     112        /** Identification of the caller. */
    144113        struct task *sender;
    145        
    146         /** Phone which was used to send the call. */
    147         phone_t *caller_phone;
    148114       
    149115        /** Private data to internal IPC. */
     
    152118        /** Data passed from/to userspace. */
    153119        ipc_data_t data;
    154 
    155         /** Method as it was sent in the request. */
    156         sysarg_t request_method;
    157 
     120       
    158121        /** Buffer for IPC_M_DATA_WRITE and IPC_M_DATA_READ. */
    159122        uint8_t *buffer;
     123       
     124        /*
     125         * The forward operation can masquerade the caller phone. For those
     126         * cases, we must keep it aside so that the answer is processed
     127         * correctly.
     128         */
     129        phone_t *caller_phone;
    160130} call_t;
    161131
     
    171141extern int ipc_forward(call_t *, phone_t *, answerbox_t *, unsigned int);
    172142extern void ipc_answer(answerbox_t *, call_t *);
    173 extern void _ipc_answer_free_call(call_t *, bool);
    174143
    175144extern void ipc_phone_init(phone_t *);
    176 extern bool ipc_phone_connect(phone_t *, answerbox_t *);
     145extern void ipc_phone_connect(phone_t *, answerbox_t *);
    177146extern int ipc_phone_hangup(phone_t *);
    178147
     
    182151extern void ipc_backsend_err(phone_t *, call_t *, sysarg_t);
    183152extern void ipc_answerbox_slam_phones(answerbox_t *, bool);
    184 extern void ipc_cleanup_call_list(answerbox_t *, list_t *);
     153extern void ipc_cleanup_call_list(list_t *);
    185154
    186155extern void ipc_print_task(task_id_t);
  • kernel/generic/include/ipc/ipcrsc.h

    r983cabe8 r3ffd4c3  
    4040
    4141extern call_t *get_call(sysarg_t);
    42 extern int phone_get(sysarg_t, phone_t **);
    4342extern int phone_alloc(task_t *);
    44 extern bool phone_connect(int, answerbox_t *);
     43extern void phone_connect(int, answerbox_t *);
    4544extern void phone_dealloc(int);
    4645
  • kernel/generic/include/proc/task.h

    r983cabe8 r3ffd4c3  
    9191       
    9292        /* IPC stuff */
    93 
    94         /** Receiving communication endpoint */
    95         answerbox_t answerbox;
    96 
    97         /** Sending communication endpoints */
     93        answerbox_t answerbox;  /**< Communication endpoint */
    9894        phone_t phones[IPC_MAX_PHONES];
    99 
    100         /** Spinlock protecting the active_calls list. */
    101         SPINLOCK_DECLARE(active_calls_lock);
    102 
    103         /**
    104          * List of all calls sent by this task that have not yet been
    105          * answered.
    106          */
    107         list_t active_calls;
    108 
     95        stats_ipc_t ipc_info;   /**< IPC statistics */
    10996        event_t events[EVENT_TASK_END - EVENT_END];
    110 
    111         /** IPC statistics */
    112         stats_ipc_t ipc_info;
    11397       
    11498#ifdef CONFIG_UDEBUG
  • kernel/generic/src/ipc/event.c

    r983cabe8 r3ffd4c3  
    163163                                call->data.task_id = TASK ? TASK->taskid : 0;
    164164                               
    165                                 irq_spinlock_lock(&event->answerbox->irq_lock,
    166                                     true);
    167                                 list_append(&call->ab_link,
    168                                     &event->answerbox->irq_notifs);
    169                                 irq_spinlock_unlock(&event->answerbox->irq_lock,
    170                                     true);
    171                                
    172                                 waitq_wakeup(&event->answerbox->wq,
    173                                     WAKEUP_FIRST);
     165                                irq_spinlock_lock(&event->answerbox->irq_lock, true);
     166                                list_append(&call->link, &event->answerbox->irq_notifs);
     167                                irq_spinlock_unlock(&event->answerbox->irq_lock, true);
     168                               
     169                                waitq_wakeup(&event->answerbox->wq, WAKEUP_FIRST);
    174170                               
    175171                                if (mask)
  • kernel/generic/src/ipc/ipc.c

    r983cabe8 r3ffd4c3  
    4545#include <ipc/kbox.h>
    4646#include <ipc/event.h>
    47 #include <ipc/sysipc_ops.h>
    48 #include <ipc/sysipc_priv.h>
    4947#include <errno.h>
    5048#include <mm/slab.h>
     
    7371{
    7472        memsetb(call, sizeof(*call), 0);
    75         spinlock_initialize(&call->forget_lock, "forget_lock");
    76         call->active = false;
    77         call->forget = false;
    7873        call->sender = TASK;
    7974        call->buffer = NULL;
     
    137132 * @param phone Initialized phone structure.
    138133 * @param box   Initialized answerbox structure.
    139  * @return      True if the phone was connected, false otherwise.
    140  */
    141 bool ipc_phone_connect(phone_t *phone, answerbox_t *box)
    142 {
    143         bool active;
    144 
     134 *
     135 */
     136void ipc_phone_connect(phone_t *phone, answerbox_t *box)
     137{
    145138        mutex_lock(&phone->lock);
     139       
     140        phone->state = IPC_PHONE_CONNECTED;
     141        phone->callee = box;
     142       
    146143        irq_spinlock_lock(&box->lock, true);
    147 
    148         active = box->active;
    149         if (active) {
    150                 phone->state = IPC_PHONE_CONNECTED;
    151                 phone->callee = box;
    152                 list_append(&phone->link, &box->connected_phones);
    153         }
    154 
     144        list_append(&phone->link, &box->connected_phones);
    155145        irq_spinlock_unlock(&box->lock, true);
     146       
    156147        mutex_unlock(&phone->lock);
    157 
    158         return active;
    159148}
    160149
     
    178167 *
    179168 */
    180 void _ipc_answer_free_call(call_t *call, bool selflocked)
    181 {
     169static void _ipc_answer_free_call(call_t *call, bool selflocked)
     170{
     171        answerbox_t *callerbox = &call->sender->answerbox;
     172        bool do_lock = ((!selflocked) || callerbox != (&TASK->answerbox));
     173       
    182174        /* Count sent answer */
    183175        irq_spinlock_lock(&TASK->lock, true);
    184176        TASK->ipc_info.answer_sent++;
    185177        irq_spinlock_unlock(&TASK->lock, true);
    186 
    187         spinlock_lock(&call->forget_lock);
    188         if (call->forget) {
    189                 /* This is a forgotten call and call->sender is not valid. */
    190                 spinlock_unlock(&call->forget_lock);
    191                 ipc_call_free(call);
    192                 return;
    193         } else {
    194                 /*
    195                  * If the call is still active, i.e. it was answered
    196                  * in a non-standard way, remove the call from the
    197                  * sender's active call list.
    198                  */
    199                 if (call->active) {
    200                         spinlock_lock(&call->sender->active_calls_lock);
    201                         list_remove(&call->ta_link);
    202                         spinlock_unlock(&call->sender->active_calls_lock);
     178       
     179        call->flags |= IPC_CALL_ANSWERED;
     180       
     181        if (call->flags & IPC_CALL_FORWARDED) {
     182                if (call->caller_phone) {
     183                        /* Demasquerade the caller phone. */
     184                        call->data.phone = call->caller_phone;
    203185                }
    204186        }
    205         spinlock_unlock(&call->forget_lock);
    206 
    207         answerbox_t *callerbox = &call->sender->answerbox;
    208         bool do_lock = ((!selflocked) || (callerbox != &TASK->answerbox));
    209        
    210         call->flags |= IPC_CALL_ANSWERED;
    211        
     187
    212188        call->data.task_id = TASK->taskid;
    213189       
     
    215191                irq_spinlock_lock(&callerbox->lock, true);
    216192       
    217         list_append(&call->ab_link, &callerbox->answers);
     193        list_append(&call->link, &callerbox->answers);
    218194       
    219195        if (do_lock)
     
    233209        /* Remove from active box */
    234210        irq_spinlock_lock(&box->lock, true);
    235         list_remove(&call->ab_link);
     211        list_remove(&call->link);
    236212        irq_spinlock_unlock(&box->lock, true);
    237213       
     
    252228void ipc_backsend_err(phone_t *phone, call_t *call, sysarg_t err)
    253229{
    254         call->caller_phone = phone;
    255230        call->data.phone = phone;
    256231        atomic_inc(&phone->active_calls);
    257 
    258         spinlock_lock(&TASK->active_calls_lock);
    259         list_append(&call->ta_link, &TASK->active_calls);
    260         spinlock_unlock(&TASK->active_calls_lock);
    261 
    262232        IPC_SET_RETVAL(call->data, err);
    263233        _ipc_answer_free_call(call, false);
     
    280250        if (!(call->flags & IPC_CALL_FORWARDED)) {
    281251                atomic_inc(&phone->active_calls);
    282 
    283                 call->caller_phone = phone;
    284                 call->active = true;
    285 
    286                 spinlock_lock(&TASK->active_calls_lock);
    287                 list_append(&call->ta_link, &TASK->active_calls);
    288                 spinlock_unlock(&TASK->active_calls_lock);
    289 
    290252                call->data.phone = phone;
    291253                call->data.task_id = TASK->taskid;
     
    293255       
    294256        irq_spinlock_lock(&box->lock, true);
    295         list_append(&call->ab_link, &box->calls);
     257        list_append(&call->link, &box->calls);
    296258        irq_spinlock_unlock(&box->lock, true);
    297259       
     
    313275        if (phone->state != IPC_PHONE_CONNECTED) {
    314276                mutex_unlock(&phone->lock);
    315                 if (!(call->flags & IPC_CALL_FORWARDED)) {
     277                if (call->flags & IPC_CALL_FORWARDED) {
     278                        IPC_SET_RETVAL(call->data, EFORWARD);
     279                        _ipc_answer_free_call(call, false);
     280                } else {
    316281                        if (phone->state == IPC_PHONE_HUNGUP)
    317282                                ipc_backsend_err(phone, call, EHANGUP);
     
    391356        TASK->ipc_info.forwarded++;
    392357        irq_spinlock_pass(&TASK->lock, &oldbox->lock);
    393         list_remove(&call->ab_link);
     358        list_remove(&call->link);
    394359        irq_spinlock_unlock(&oldbox->lock, true);
    395360       
    396361        if (mode & IPC_FF_ROUTE_FROM_ME) {
     362                if (!call->caller_phone)
     363                        call->caller_phone = call->data.phone;
    397364                call->data.phone = newphone;
    398365                call->data.task_id = TASK->taskid;
     
    439406               
    440407                request = list_get_instance(list_first(&box->irq_notifs),
    441                     call_t, ab_link);
    442                 list_remove(&request->ab_link);
     408                    call_t, link);
     409                list_remove(&request->link);
    443410               
    444411                irq_spinlock_unlock(&box->irq_lock, false);
     
    449416                /* Handle asynchronous answers */
    450417                request = list_get_instance(list_first(&box->answers),
    451                     call_t, ab_link);
    452                 list_remove(&request->ab_link);
    453                 atomic_dec(&request->caller_phone->active_calls);
     418                    call_t, link);
     419                list_remove(&request->link);
     420                atomic_dec(&request->data.phone->active_calls);
    454421        } else if (!list_empty(&box->calls)) {
    455422                /* Count received call */
     
    458425                /* Handle requests */
    459426                request = list_get_instance(list_first(&box->calls),
    460                     call_t, ab_link);
    461                 list_remove(&request->ab_link);
     427                    call_t, link);
     428                list_remove(&request->link);
    462429               
    463430                /* Append request to dispatch queue */
    464                 list_append(&request->ab_link, &box->dispatched_calls);
     431                list_append(&request->link, &box->dispatched_calls);
    465432        } else {
    466433                /* This can happen regularly after ipc_cleanup */
     
    482449/** Answer all calls from list with EHANGUP answer.
    483450 *
    484  * @param box Answerbox with the list.
    485451 * @param lst Head of the list to be cleaned up.
    486  */
    487 void ipc_cleanup_call_list(answerbox_t *box, list_t *lst)
    488 {
    489         irq_spinlock_lock(&box->lock, true);
     452 *
     453 */
     454void ipc_cleanup_call_list(list_t *lst)
     455{
    490456        while (!list_empty(lst)) {
    491                 call_t *call = list_get_instance(list_first(lst), call_t,
    492                     ab_link);
    493                
    494                 list_remove(&call->ab_link);
    495 
    496                 irq_spinlock_unlock(&box->lock, true);
    497 
    498                 ipc_data_t old = call->data;
     457                call_t *call = list_get_instance(list_first(lst), call_t, link);
     458                if (call->buffer)
     459                        free(call->buffer);
     460               
     461                list_remove(&call->link);
     462               
    499463                IPC_SET_RETVAL(call->data, EHANGUP);
    500                 answer_preprocess(call, &old);
    501464                _ipc_answer_free_call(call, true);
    502 
    503                 irq_spinlock_lock(&box->lock, true);
    504         }
    505         irq_spinlock_unlock(&box->lock, true);
     465        }
    506466}
    507467
     
    569529}
    570530
    571 static void ipc_forget_all_active_calls(void)
    572 {
    573         call_t *call;
    574 
    575 restart:
    576         spinlock_lock(&TASK->active_calls_lock);
    577         if (list_empty(&TASK->active_calls)) {
    578                 /*
    579                  * We are done, there are no more active calls.
    580                  * Nota bene: there may still be answers waiting for pick up.
    581                  */
    582                 spinlock_unlock(&TASK->active_calls_lock);     
    583                 return;
    584         }
    585        
    586         call = list_get_instance(list_first(&TASK->active_calls), call_t,
    587             ta_link);
    588 
    589         if (!spinlock_trylock(&call->forget_lock)) {
    590                 /*
    591                  * Avoid deadlock and let async_answer() or
    592                  *  _ipc_answer_free_call() win the race to dequeue the first
    593                  * call on the list.
    594                  */
    595                 spinlock_unlock(&TASK->active_calls_lock);     
    596                 goto restart;
    597         }
    598 
    599         /*
    600          * Forget the call and donate it to the task which holds up the answer.
    601          */
    602 
    603         call->forget = true;
    604         call->sender = NULL;
    605         list_remove(&call->ta_link);
    606 
    607         spinlock_unlock(&call->forget_lock);
    608         spinlock_unlock(&TASK->active_calls_lock);
    609 
    610         atomic_dec(&call->caller_phone->active_calls);
    611 
    612         sysipc_ops_t *ops = sysipc_ops_get(call->request_method);
    613         if (ops->request_forget)
    614                 ops->request_forget(call);
    615 
    616         goto restart;
    617 }
    618 
    619 /** Wait for all answers to asynchronous calls to arrive. */
    620 static void ipc_wait_for_all_answered_calls(void)
    621 {
    622         call_t *call;
    623         size_t i;
    624 
    625 restart:
    626         /*
    627          * Go through all phones, until they are all free.
    628          * Locking is needed as there may be connection handshakes in progress.
    629          */
    630         for (i = 0; i < IPC_MAX_PHONES; i++) {
    631                 phone_t *phone = &TASK->phones[i];
    632 
    633                 mutex_lock(&phone->lock);       
    634                 if ((phone->state == IPC_PHONE_HUNGUP) &&
    635                     (atomic_get(&phone->active_calls) == 0)) {
    636                         phone->state = IPC_PHONE_FREE;
    637                         phone->callee = NULL;
    638                 }
    639 
    640                 /*
    641                  * We might have had some IPC_PHONE_CONNECTING phones at the
    642                  * beginning of ipc_cleanup(). Depending on whether these were
    643                  * forgotten or answered, they will eventually enter the
    644                  * IPC_PHONE_FREE or IPC_PHONE_CONNECTED states, respectively.
    645                  * In the latter case, the other side may slam the open phones
    646                  * at any time, in which case we will get an IPC_PHONE_SLAMMED
    647                  * phone.
    648                  */
    649                 if ((phone->state == IPC_PHONE_CONNECTED) ||
    650                     (phone->state == IPC_PHONE_SLAMMED)) {
    651                         mutex_unlock(&phone->lock);
    652                         ipc_phone_hangup(phone);
    653                         /*
    654                          * Now there may be one extra active call, which needs
    655                          * to be forgotten.
    656                          */
    657                         ipc_forget_all_active_calls();
    658                         goto restart;
    659                 }
    660 
    661                 /*
    662                  * If the hangup succeeded, it has sent a HANGUP message, the
    663                  * IPC is now in HUNGUP state, we wait for the reply to come
    664                  */
    665                 if (phone->state != IPC_PHONE_FREE) {
    666                         mutex_unlock(&phone->lock);
    667                         break;
    668                 }
    669 
    670                 mutex_unlock(&phone->lock);
    671         }
    672                
    673         /* Got into cleanup */
    674         if (i == IPC_MAX_PHONES)
    675                 return;
    676                
    677         call = ipc_wait_for_call(&TASK->answerbox, SYNCH_NO_TIMEOUT,
    678             SYNCH_FLAGS_NONE);
    679         ASSERT(call->flags & (IPC_CALL_ANSWERED | IPC_CALL_NOTIF));
    680         ipc_call_free(call);
    681         goto restart;
    682 }
    683 
    684531/** Clean up all IPC communication of the current task.
    685532 *
     
    690537void ipc_cleanup(void)
    691538{
    692         /*
    693          * Mark the answerbox as inactive.
    694          *
    695          * The main purpose for doing this is to prevent any pending callback
    696          * connections from getting established beyond this point.
    697          */
    698         irq_spinlock_lock(&TASK->answerbox.lock, true);
    699         TASK->answerbox.active = false;
    700         irq_spinlock_unlock(&TASK->answerbox.lock, true);
    701 
    702539        /* Disconnect all our phones ('ipc_phone_hangup') */
    703         for (size_t i = 0; i < IPC_MAX_PHONES; i++)
     540        size_t i;
     541        for (i = 0; i < IPC_MAX_PHONES; i++)
    704542                ipc_phone_hangup(&TASK->phones[i]);
    705543       
     
    719557       
    720558        /* Answer all messages in 'calls' and 'dispatched_calls' queues */
    721         ipc_cleanup_call_list(&TASK->answerbox,
    722             &TASK->answerbox.dispatched_calls);
    723         ipc_cleanup_call_list(&TASK->answerbox, &TASK->answerbox.calls);
    724 
    725         ipc_forget_all_active_calls();
    726         ipc_wait_for_all_answered_calls();
     559        irq_spinlock_lock(&TASK->answerbox.lock, true);
     560        ipc_cleanup_call_list(&TASK->answerbox.dispatched_calls);
     561        ipc_cleanup_call_list(&TASK->answerbox.calls);
     562        irq_spinlock_unlock(&TASK->answerbox.lock, true);
     563       
     564        /* Wait for all answers to asynchronous calls to arrive */
     565        while (true) {
     566                /*
     567                 * Go through all phones, until they are all FREE
     568                 * Locking is not needed, no one else should modify
     569                 * it when we are in cleanup
     570                 */
     571                for (i = 0; i < IPC_MAX_PHONES; i++) {
     572                        if (TASK->phones[i].state == IPC_PHONE_HUNGUP &&
     573                            atomic_get(&TASK->phones[i].active_calls) == 0) {
     574                                TASK->phones[i].state = IPC_PHONE_FREE;
     575                                TASK->phones[i].callee = NULL;
     576                        }
     577                       
     578                        /*
     579                         * Just for sure, we might have had some
     580                         * IPC_PHONE_CONNECTING phones
     581                         */
     582                        if (TASK->phones[i].state == IPC_PHONE_CONNECTED)
     583                                ipc_phone_hangup(&TASK->phones[i]);
     584                       
     585                        /*
     586                         * If the hangup succeeded, it has sent a HANGUP
     587                         * message, the IPC is now in HUNGUP state, we
     588                         * wait for the reply to come
     589                         */
     590                       
     591                        if (TASK->phones[i].state != IPC_PHONE_FREE)
     592                                break;
     593                }
     594               
     595                /* Got into cleanup */
     596                if (i == IPC_MAX_PHONES)
     597                        break;
     598               
     599                call_t *call = ipc_wait_for_call(&TASK->answerbox, SYNCH_NO_TIMEOUT,
     600                    SYNCH_FLAGS_NONE);
     601                ASSERT((call->flags & IPC_CALL_ANSWERED) ||
     602                    (call->flags & IPC_CALL_NOTIF));
     603               
     604                ipc_call_free(call);
     605        }
    727606}
    728607
     
    736615        ipc_answerbox_slab = slab_cache_create("answerbox_t",
    737616            sizeof(answerbox_t), 0, NULL, NULL, 0);
    738 }
    739 
    740 
    741 static void ipc_print_call_list(list_t *list)
    742 {
    743         list_foreach(*list, cur) {
    744                 call_t *call = list_get_instance(cur, call_t, ab_link);
    745                
    746 #ifdef __32_BITS__
    747                 printf("%10p ", call);
    748 #endif
    749                
    750 #ifdef __64_BITS__
    751                 printf("%18p ", call);
    752 #endif
    753                
    754                 spinlock_lock(&call->forget_lock);
    755 
    756                 printf("%-8" PRIun " %-6" PRIun " %-6" PRIun " %-6" PRIun
    757                     " %-6" PRIun " %-6" PRIun " %-7x",
    758                     IPC_GET_IMETHOD(call->data), IPC_GET_ARG1(call->data),
    759                     IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data),
    760                     IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data),
    761                     call->flags);
    762 
    763                 if (call->forget) {
    764                         printf(" ? (call forgotten)\n");
    765                 } else {
    766                         printf(" %" PRIu64 " (%s)\n",
    767                             call->sender->taskid, call->sender->name);
    768                 }
    769 
    770                 spinlock_unlock(&call->forget_lock);
    771         }
    772617}
    773618
     
    843688       
    844689        printf(" --- incomming calls ---\n");
    845         ipc_print_call_list(&task->answerbox.calls);
     690        list_foreach(task->answerbox.calls, cur) {
     691                call_t *call = list_get_instance(cur, call_t, link);
     692               
     693#ifdef __32_BITS__
     694                printf("%10p ", call);
     695#endif
     696               
     697#ifdef __64_BITS__
     698                printf("%18p ", call);
     699#endif
     700               
     701                printf("%-8" PRIun " %-6" PRIun " %-6" PRIun " %-6" PRIun
     702                    " %-6" PRIun " %-6" PRIun " %-7x %" PRIu64 " (%s)\n",
     703                    IPC_GET_IMETHOD(call->data), IPC_GET_ARG1(call->data),
     704                    IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data),
     705                    IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data),
     706                    call->flags, call->sender->taskid, call->sender->name);
     707        }
     708       
    846709        printf(" --- dispatched calls ---\n");
    847         ipc_print_call_list(&task->answerbox.dispatched_calls);
     710        list_foreach(task->answerbox.dispatched_calls, cur) {
     711                call_t *call = list_get_instance(cur, call_t, link);
     712               
     713#ifdef __32_BITS__
     714                printf("%10p ", call);
     715#endif
     716               
     717#ifdef __64_BITS__
     718                printf("%18p ", call);
     719#endif
     720               
     721                printf("%-8" PRIun " %-6" PRIun " %-6" PRIun " %-6" PRIun
     722                    " %-6" PRIun " %-6" PRIun " %-7x %" PRIu64 " (%s)\n",
     723                    IPC_GET_IMETHOD(call->data), IPC_GET_ARG1(call->data),
     724                    IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data),
     725                    IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data),
     726                    call->flags, call->sender->taskid, call->sender->name);
     727        }
     728       
    848729        printf(" --- incoming answers ---\n");
    849         ipc_print_call_list(&task->answerbox.answers);
     730        list_foreach(task->answerbox.answers, cur) {
     731                call_t *call = list_get_instance(cur, call_t, link);
     732               
     733#ifdef __32_BITS__
     734                printf("%10p ", call);
     735#endif
     736               
     737#ifdef __64_BITS__
     738                printf("%18p ", call);
     739#endif
     740               
     741                printf("%-8" PRIun " %-6" PRIun " %-6" PRIun " %-6" PRIun
     742                    " %-6" PRIun " %-6" PRIun " %-7x %" PRIu64 " (%s)\n",
     743                    IPC_GET_IMETHOD(call->data), IPC_GET_ARG1(call->data),
     744                    IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data),
     745                    IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data),
     746                    call->flags, call->sender->taskid, call->sender->name);
     747        }
    850748       
    851749        irq_spinlock_unlock(&task->answerbox.lock, false);
  • kernel/generic/src/ipc/ipcrsc.c

    r983cabe8 r3ffd4c3  
    132132#include <ipc/ipcrsc.h>
    133133#include <debug.h>
    134 #include <abi/errno.h>
    135134
    136135/** Find call_t * in call table according to callid.
     
    152151       
    153152        list_foreach(TASK->answerbox.dispatched_calls, lst) {
    154                 call_t *call = list_get_instance(lst, call_t, ab_link);
     153                call_t *call = list_get_instance(lst, call_t, link);
    155154                if ((sysarg_t) call == callid) {
    156155                        result = call;
     
    161160        irq_spinlock_unlock(&TASK->answerbox.lock, true);
    162161        return result;
    163 }
    164 
    165 /** Get phone from the current task by ID.
    166  *
    167  * @param phoneid Phone ID.
    168  * @param phone   Place to store pointer to phone.
    169  *
    170  * @return EOK on success, EINVAL if ID is invalid.
    171  *
    172  */
    173 int phone_get(sysarg_t phoneid, phone_t **phone)
    174 {
    175         if (phoneid >= IPC_MAX_PHONES)
    176                 return EINVAL;
    177        
    178         *phone = &TASK->phones[phoneid];
    179         return EOK;
    180162}
    181163
     
    241223 * @param phoneid Phone handle to be connected.
    242224 * @param box     Answerbox to which to connect the phone handle.
    243  * @return        True if the phone was connected, false otherwise.
    244225 *
    245226 * The procedure _enforces_ that the user first marks the phone
     
    248229 *
    249230 */
    250 bool phone_connect(int phoneid, answerbox_t *box)
     231void phone_connect(int phoneid, answerbox_t *box)
    251232{
    252233        phone_t *phone = &TASK->phones[phoneid];
    253234       
    254235        ASSERT(phone->state == IPC_PHONE_CONNECTING);
    255         return ipc_phone_connect(phone, box);
     236        ipc_phone_connect(phone, box);
    256237}
    257238
  • kernel/generic/src/ipc/irq.c

    r983cabe8 r3ffd4c3  
    510510{
    511511        irq_spinlock_lock(&irq->notif_cfg.answerbox->irq_lock, false);
    512         list_append(&call->ab_link, &irq->notif_cfg.answerbox->irq_notifs);
     512        list_append(&call->link, &irq->notif_cfg.answerbox->irq_notifs);
    513513        irq_spinlock_unlock(&irq->notif_cfg.answerbox->irq_lock, false);
    514514       
  • kernel/generic/src/ipc/kbox.c

    r983cabe8 r3ffd4c3  
    4848{
    4949        /*
    50          * Not really needed, just to be consistent with the meaning of
    51          * answerbox_t.active.
    52          */
    53         irq_spinlock_lock(&TASK->kb.box.lock, true);
    54         TASK->kb.box.active = false;
    55         irq_spinlock_unlock(&TASK->kb.box.lock, true);
    56 
    57         /*
    5850         * Only hold kb.cleanup_lock while setting kb.finished -
    5951         * this is enough.
     
    9688       
    9789        /* Answer all messages in 'calls' and 'dispatched_calls' queues. */
    98         ipc_cleanup_call_list(&TASK->kb.box, &TASK->kb.box.dispatched_calls);
    99         ipc_cleanup_call_list(&TASK->kb.box, &TASK->kb.box.calls);
     90        irq_spinlock_lock(&TASK->kb.box.lock, true);
     91        ipc_cleanup_call_list(&TASK->kb.box.dispatched_calls);
     92        ipc_cleanup_call_list(&TASK->kb.box.calls);
     93        irq_spinlock_unlock(&TASK->kb.box.lock, true);
    10094}
    10195
     
    242236       
    243237        /* Connect the newly allocated phone to the kbox */
    244         (void) ipc_phone_connect(&TASK->phones[newphid], &task->kb.box);
     238        ipc_phone_connect(&TASK->phones[newphid], &task->kb.box);
    245239       
    246240        if (task->kb.thread != NULL) {
  • kernel/generic/src/ipc/sysipc.c

    r983cabe8 r3ffd4c3  
    3434
    3535#include <arch.h>
     36#include <proc/task.h>
     37#include <proc/thread.h>
    3638#include <errno.h>
    3739#include <memstr.h>
     40#include <debug.h>
    3841#include <ipc/ipc.h>
    3942#include <abi/ipc/methods.h>
    4043#include <ipc/sysipc.h>
    41 #include <ipc/sysipc_ops.h>
    42 #include <ipc/sysipc_priv.h>
    4344#include <ipc/irq.h>
    4445#include <ipc/ipcrsc.h>
     
    4647#include <ipc/kbox.h>
    4748#include <synch/waitq.h>
     49#include <udebug/udebug_ipc.h>
    4850#include <arch/interrupt.h>
    4951#include <syscall/copy.h>
    5052#include <security/cap.h>
    5153#include <console/console.h>
     54#include <mm/as.h>
    5255#include <print.h>
    5356#include <macros.h>
    5457
     58/**
     59 * Maximum buffer size allowed for IPC_M_DATA_WRITE and IPC_M_DATA_READ
     60 * requests.
     61 */
     62#define DATA_XFER_LIMIT  (64 * 1024)
     63
    5564#define STRUCT_TO_USPACE(dst, src)  copy_to_uspace((dst), (src), sizeof(*(src)))
     65
     66/** Get phone from the current task by ID.
     67 *
     68 * @param phoneid Phone ID.
     69 * @param phone   Place to store pointer to phone.
     70 *
     71 * @return EOK on success, EINVAL if ID is invalid.
     72 *
     73 */
     74static int phone_get(sysarg_t phoneid, phone_t **phone)
     75{
     76        if (phoneid >= IPC_MAX_PHONES)
     77                return EINVAL;
     78       
     79        *phone = &TASK->phones[phoneid];
     80        return EOK;
     81}
    5682
    5783/** Decide if the interface and method is a system method.
     
    155181 * @param olddata Saved data of the request.
    156182 *
    157  * @return Return EOK on success or a negative error code.
    158  *
    159  */
    160 int answer_preprocess(call_t *answer, ipc_data_t *olddata)
    161 {
    162         int rc = EOK;
    163         sysipc_ops_t *ops;
    164 
    165         spinlock_lock(&answer->forget_lock);
    166         if (answer->forget) {
    167                 /*
    168                  * This is a forgotten call and answer->sender is not valid.
     183 * @return Return 0 on success or an error code.
     184 *
     185 */
     186static inline int answer_preprocess(call_t *answer, ipc_data_t *olddata)
     187{
     188        if ((native_t) IPC_GET_RETVAL(answer->data) == EHANGUP) {
     189                /* In case of forward, hangup the forwared phone,
     190                 * not the originator
    169191                 */
    170                 spinlock_unlock(&answer->forget_lock);
    171 
    172                 ops = sysipc_ops_get(answer->request_method);
    173                 if (ops->answer_cleanup)
    174                         ops->answer_cleanup(answer, olddata);
    175 
    176                 return rc;
    177         } else {
    178                 ASSERT(answer->active);
    179 
    180                 /*
    181                  * Mark the call as inactive to prevent _ipc_answer_free_call()
    182                  * from attempting to remove the call from the active list
    183                  * itself.
    184                  */
    185                 answer->active = false;
    186 
    187                 /*
    188                  * Remove the call from the sender's active call list.
    189                  * We enforce this locking order so that any potential
    190                  * concurrently executing forget operation is forced to
    191                  * release its active_calls_lock and lose the race to
    192                  * forget this soon to be answered call.
    193                  */
    194                 spinlock_lock(&answer->sender->active_calls_lock);
    195                 list_remove(&answer->ta_link);
    196                 spinlock_unlock(&answer->sender->active_calls_lock);
    197         }
    198         spinlock_unlock(&answer->forget_lock);
    199 
    200         if ((native_t) IPC_GET_RETVAL(answer->data) == EHANGUP) {
    201                 phone_t *phone = answer->caller_phone;
    202                 mutex_lock(&phone->lock);
    203                 if (phone->state == IPC_PHONE_CONNECTED) {
    204                         irq_spinlock_lock(&phone->callee->lock, true);
    205                         list_remove(&phone->link);
    206                         phone->state = IPC_PHONE_SLAMMED;
    207                         irq_spinlock_unlock(&phone->callee->lock, true);
    208                 }
    209                 mutex_unlock(&phone->lock);
     192                mutex_lock(&answer->data.phone->lock);
     193                irq_spinlock_lock(&TASK->answerbox.lock, true);
     194                if (answer->data.phone->state == IPC_PHONE_CONNECTED) {
     195                        list_remove(&answer->data.phone->link);
     196                        answer->data.phone->state = IPC_PHONE_SLAMMED;
     197                }
     198                irq_spinlock_unlock(&TASK->answerbox.lock, true);
     199                mutex_unlock(&answer->data.phone->lock);
    210200        }
    211201       
    212202        if (!olddata)
    213                 return rc;
    214 
    215         ops = sysipc_ops_get(answer->request_method);
    216         if (ops->answer_preprocess)
    217                 rc = ops->answer_preprocess(answer, olddata);
    218        
    219         return rc;
     203                return 0;
     204       
     205        if (IPC_GET_IMETHOD(*olddata) == IPC_M_CONNECTION_CLONE) {
     206                int phoneid = IPC_GET_ARG1(*olddata);
     207                phone_t *phone = &TASK->phones[phoneid];
     208               
     209                if (IPC_GET_RETVAL(answer->data) != EOK) {
     210                        /*
     211                         * The recipient of the cloned phone rejected the offer.
     212                         * In this case, the connection was established at the
     213                         * request time and therefore we need to slam the phone.
     214                         * We don't merely hangup as that would result in
     215                         * sending IPC_M_HUNGUP to the third party on the
     216                         * other side of the cloned phone.
     217                         */
     218                        mutex_lock(&phone->lock);
     219                        if (phone->state == IPC_PHONE_CONNECTED) {
     220                                irq_spinlock_lock(&phone->callee->lock, true);
     221                                list_remove(&phone->link);
     222                                phone->state = IPC_PHONE_SLAMMED;
     223                                irq_spinlock_unlock(&phone->callee->lock, true);
     224                        }
     225                        mutex_unlock(&phone->lock);
     226                }
     227        } else if (IPC_GET_IMETHOD(*olddata) == IPC_M_CLONE_ESTABLISH) {
     228                phone_t *phone = (phone_t *) IPC_GET_ARG5(*olddata);
     229               
     230                if (IPC_GET_RETVAL(answer->data) != EOK) {
     231                        /*
     232                         * The other party on the cloned phoned rejected our
     233                         * request for connection on the protocol level.
     234                         * We need to break the connection without sending
     235                         * IPC_M_HUNGUP back.
     236                         */
     237                        mutex_lock(&phone->lock);
     238                        if (phone->state == IPC_PHONE_CONNECTED) {
     239                                irq_spinlock_lock(&phone->callee->lock, true);
     240                                list_remove(&phone->link);
     241                                phone->state = IPC_PHONE_SLAMMED;
     242                                irq_spinlock_unlock(&phone->callee->lock, true);
     243                        }
     244                        mutex_unlock(&phone->lock);
     245                }
     246        } else if (IPC_GET_IMETHOD(*olddata) == IPC_M_CONNECT_TO_ME) {
     247                int phoneid = IPC_GET_ARG5(*olddata);
     248               
     249                if (IPC_GET_RETVAL(answer->data) != EOK) {
     250                        /* The connection was not accepted */
     251                        phone_dealloc(phoneid);
     252                } else {
     253                        /* The connection was accepted */
     254                        phone_connect(phoneid, &answer->sender->answerbox);
     255                        /* Set 'phone hash' as arg5 of response */
     256                        IPC_SET_ARG5(answer->data,
     257                            (sysarg_t) &TASK->phones[phoneid]);
     258                }
     259        } else if (IPC_GET_IMETHOD(*olddata) == IPC_M_CONNECT_ME_TO) {
     260                /* If the users accepted call, connect */
     261                if (IPC_GET_RETVAL(answer->data) == EOK) {
     262                        ipc_phone_connect((phone_t *) IPC_GET_ARG5(*olddata),
     263                            &TASK->answerbox);
     264                }
     265        } else if (IPC_GET_IMETHOD(*olddata) == IPC_M_SHARE_OUT) {
     266                if (!IPC_GET_RETVAL(answer->data)) {
     267                        /* Accepted, handle as_area receipt */
     268                       
     269                        irq_spinlock_lock(&answer->sender->lock, true);
     270                        as_t *as = answer->sender->as;
     271                        irq_spinlock_unlock(&answer->sender->lock, true);
     272                       
     273                        uintptr_t dst_base = (uintptr_t) -1;
     274                        int rc = as_area_share(as, IPC_GET_ARG1(*olddata),
     275                            IPC_GET_ARG2(*olddata), AS, IPC_GET_ARG3(*olddata),
     276                            &dst_base, IPC_GET_ARG1(answer->data));
     277                       
     278                        if (rc == EOK)
     279                                rc = copy_to_uspace((void *) IPC_GET_ARG2(answer->data),
     280                                    &dst_base, sizeof(dst_base));
     281                       
     282                        IPC_SET_RETVAL(answer->data, rc);
     283                        return rc;
     284                }
     285        } else if (IPC_GET_IMETHOD(*olddata) == IPC_M_SHARE_IN) {
     286                if (!IPC_GET_RETVAL(answer->data)) {
     287                        irq_spinlock_lock(&answer->sender->lock, true);
     288                        as_t *as = answer->sender->as;
     289                        irq_spinlock_unlock(&answer->sender->lock, true);
     290                       
     291                        uintptr_t dst_base = (uintptr_t) -1;
     292                        int rc = as_area_share(AS, IPC_GET_ARG1(answer->data),
     293                            IPC_GET_ARG1(*olddata), as, IPC_GET_ARG2(answer->data),
     294                            &dst_base, IPC_GET_ARG3(answer->data));
     295                        IPC_SET_ARG4(answer->data, dst_base);
     296                        IPC_SET_RETVAL(answer->data, rc);
     297                }
     298        } else if (IPC_GET_IMETHOD(*olddata) == IPC_M_DATA_READ) {
     299                ASSERT(!answer->buffer);
     300                if (!IPC_GET_RETVAL(answer->data)) {
     301                        /* The recipient agreed to send data. */
     302                        uintptr_t src = IPC_GET_ARG1(answer->data);
     303                        uintptr_t dst = IPC_GET_ARG1(*olddata);
     304                        size_t max_size = IPC_GET_ARG2(*olddata);
     305                        size_t size = IPC_GET_ARG2(answer->data);
     306                        if (size && size <= max_size) {
     307                                /*
     308                                 * Copy the destination VA so that this piece of
     309                                 * information is not lost.
     310                                 */
     311                                IPC_SET_ARG1(answer->data, dst);
     312                               
     313                                answer->buffer = malloc(size, 0);
     314                                int rc = copy_from_uspace(answer->buffer,
     315                                    (void *) src, size);
     316                                if (rc) {
     317                                        IPC_SET_RETVAL(answer->data, rc);
     318                                        free(answer->buffer);
     319                                        answer->buffer = NULL;
     320                                }
     321                        } else if (!size) {
     322                                IPC_SET_RETVAL(answer->data, EOK);
     323                        } else {
     324                                IPC_SET_RETVAL(answer->data, ELIMIT);
     325                        }
     326                }
     327        } else if (IPC_GET_IMETHOD(*olddata) == IPC_M_DATA_WRITE) {
     328                ASSERT(answer->buffer);
     329                if (!IPC_GET_RETVAL(answer->data)) {
     330                        /* The recipient agreed to receive data. */
     331                        uintptr_t dst = (uintptr_t)IPC_GET_ARG1(answer->data);
     332                        size_t size = (size_t)IPC_GET_ARG2(answer->data);
     333                        size_t max_size = (size_t)IPC_GET_ARG2(*olddata);
     334                       
     335                        if (size <= max_size) {
     336                                int rc = copy_to_uspace((void *) dst,
     337                                    answer->buffer, size);
     338                                if (rc)
     339                                        IPC_SET_RETVAL(answer->data, rc);
     340                        } else {
     341                                IPC_SET_RETVAL(answer->data, ELIMIT);
     342                        }
     343                }
     344                free(answer->buffer);
     345                answer->buffer = NULL;
     346        } else if (IPC_GET_IMETHOD(*olddata) == IPC_M_STATE_CHANGE_AUTHORIZE) {
     347                if (!IPC_GET_RETVAL(answer->data)) {
     348                        /* The recipient authorized the change of state. */
     349                        phone_t *recipient_phone;
     350                        task_t *other_task_s;
     351                        task_t *other_task_r;
     352                        int rc;
     353
     354                        rc = phone_get(IPC_GET_ARG1(answer->data),
     355                            &recipient_phone);
     356                        if (rc != EOK) {
     357                                IPC_SET_RETVAL(answer->data, ENOENT);
     358                                return ENOENT;
     359                        }
     360
     361                        mutex_lock(&recipient_phone->lock);
     362                        if (recipient_phone->state != IPC_PHONE_CONNECTED) {
     363                                mutex_unlock(&recipient_phone->lock);
     364                                IPC_SET_RETVAL(answer->data, EINVAL);
     365                                return EINVAL;
     366                        }
     367
     368                        other_task_r = recipient_phone->callee->task;
     369                        other_task_s = (task_t *) IPC_GET_ARG5(*olddata);
     370
     371                        /*
     372                         * See if both the sender and the recipient meant the
     373                         * same third party task.
     374                         */
     375                        if (other_task_r != other_task_s) {
     376                                IPC_SET_RETVAL(answer->data, EINVAL);
     377                                rc = EINVAL;
     378                        } else {
     379                                rc = event_task_notify_5(other_task_r,
     380                                    EVENT_TASK_STATE_CHANGE, false,
     381                                    IPC_GET_ARG1(*olddata),
     382                                    IPC_GET_ARG2(*olddata),
     383                                    IPC_GET_ARG3(*olddata),
     384                                    LOWER32(olddata->task_id),
     385                                    UPPER32(olddata->task_id));
     386                                IPC_SET_RETVAL(answer->data, rc);
     387                        }
     388
     389                        mutex_unlock(&recipient_phone->lock);
     390                        return rc;
     391                }
     392        }
     393       
     394        return 0;
     395}
     396
     397static void phones_lock(phone_t *p1, phone_t *p2)
     398{
     399        if (p1 < p2) {
     400                mutex_lock(&p1->lock);
     401                mutex_lock(&p2->lock);
     402        } else if (p1 > p2) {
     403                mutex_lock(&p2->lock);
     404                mutex_lock(&p1->lock);
     405        } else
     406                mutex_lock(&p1->lock);
     407}
     408
     409static void phones_unlock(phone_t *p1, phone_t *p2)
     410{
     411        mutex_unlock(&p1->lock);
     412        if (p1 != p2)
     413                mutex_unlock(&p2->lock);
    220414}
    221415
     
    230424static int request_preprocess(call_t *call, phone_t *phone)
    231425{
    232         int rc = EOK;
    233 
    234         call->request_method = IPC_GET_IMETHOD(call->data);
    235 
    236         sysipc_ops_t *ops = sysipc_ops_get(call->request_method);
    237         if (ops->request_preprocess)
    238                 rc = ops->request_preprocess(call, phone);
    239        
    240         return rc;
     426        switch (IPC_GET_IMETHOD(call->data)) {
     427        case IPC_M_CONNECTION_CLONE: {
     428                phone_t *cloned_phone;
     429                if (phone_get(IPC_GET_ARG1(call->data), &cloned_phone) != EOK)
     430                        return ENOENT;
     431               
     432                phones_lock(cloned_phone, phone);
     433               
     434                if ((cloned_phone->state != IPC_PHONE_CONNECTED) ||
     435                    phone->state != IPC_PHONE_CONNECTED) {
     436                        phones_unlock(cloned_phone, phone);
     437                        return EINVAL;
     438                }
     439               
     440                /*
     441                 * We can be pretty sure now that both tasks exist and we are
     442                 * connected to them. As we continue to hold the phone locks,
     443                 * we are effectively preventing them from finishing their
     444                 * potential cleanup.
     445                 *
     446                 */
     447                int newphid = phone_alloc(phone->callee->task);
     448                if (newphid < 0) {
     449                        phones_unlock(cloned_phone, phone);
     450                        return ELIMIT;
     451                }
     452               
     453                ipc_phone_connect(&phone->callee->task->phones[newphid],
     454                    cloned_phone->callee);
     455                phones_unlock(cloned_phone, phone);
     456               
     457                /* Set the new phone for the callee. */
     458                IPC_SET_ARG1(call->data, newphid);
     459                break;
     460        }
     461        case IPC_M_CLONE_ESTABLISH:
     462                IPC_SET_ARG5(call->data, (sysarg_t) phone);
     463                break;
     464        case IPC_M_CONNECT_ME_TO: {
     465                int newphid = phone_alloc(TASK);
     466                if (newphid < 0)
     467                        return ELIMIT;
     468               
     469                /* Set arg5 for server */
     470                IPC_SET_ARG5(call->data, (sysarg_t) &TASK->phones[newphid]);
     471                call->flags |= IPC_CALL_CONN_ME_TO;
     472                call->priv = newphid;
     473                break;
     474        }
     475        case IPC_M_SHARE_OUT: {
     476                size_t size = as_area_get_size(IPC_GET_ARG1(call->data));
     477                if (!size)
     478                        return EPERM;
     479               
     480                IPC_SET_ARG2(call->data, size);
     481                break;
     482        }
     483        case IPC_M_DATA_READ: {
     484                size_t size = IPC_GET_ARG2(call->data);
     485                if (size > DATA_XFER_LIMIT) {
     486                        int flags = IPC_GET_ARG3(call->data);
     487                        if (flags & IPC_XF_RESTRICT)
     488                                IPC_SET_ARG2(call->data, DATA_XFER_LIMIT);
     489                        else
     490                                return ELIMIT;
     491                }
     492                break;
     493        }
     494        case IPC_M_DATA_WRITE: {
     495                uintptr_t src = IPC_GET_ARG1(call->data);
     496                size_t size = IPC_GET_ARG2(call->data);
     497               
     498                if (size > DATA_XFER_LIMIT) {
     499                        int flags = IPC_GET_ARG3(call->data);
     500                        if (flags & IPC_XF_RESTRICT) {
     501                                size = DATA_XFER_LIMIT;
     502                                IPC_SET_ARG2(call->data, size);
     503                        } else
     504                                return ELIMIT;
     505                }
     506               
     507                call->buffer = (uint8_t *) malloc(size, 0);
     508                int rc = copy_from_uspace(call->buffer, (void *) src, size);
     509                if (rc != 0) {
     510                        free(call->buffer);
     511                        return rc;
     512                }
     513               
     514                break;
     515        }
     516        case IPC_M_STATE_CHANGE_AUTHORIZE: {
     517                phone_t *sender_phone;
     518                task_t *other_task_s;
     519
     520                if (phone_get(IPC_GET_ARG5(call->data), &sender_phone) != EOK)
     521                        return ENOENT;
     522
     523                mutex_lock(&sender_phone->lock);
     524                if (sender_phone->state != IPC_PHONE_CONNECTED) {
     525                        mutex_unlock(&sender_phone->lock);
     526                        return EINVAL;
     527                }
     528
     529                other_task_s = sender_phone->callee->task;
     530
     531                mutex_unlock(&sender_phone->lock);
     532
     533                /* Remember the third party task hash. */
     534                IPC_SET_ARG5(call->data, (sysarg_t) other_task_s);
     535                break;
     536        }
     537#ifdef CONFIG_UDEBUG
     538        case IPC_M_DEBUG:
     539                return udebug_request_preprocess(call, phone);
     540#endif
     541        default:
     542                break;
     543        }
     544       
     545        return 0;
    241546}
    242547
     
    256561                IPC_SET_RETVAL(call->data, EFORWARD);
    257562       
    258         sysipc_ops_t *ops = sysipc_ops_get(call->request_method);
    259         if (ops->answer_process)
    260                 (void) ops->answer_process(call);
    261 }
    262 
     563        if (call->flags & IPC_CALL_CONN_ME_TO) {
     564                if (IPC_GET_RETVAL(call->data))
     565                        phone_dealloc(call->priv);
     566                else
     567                        IPC_SET_ARG5(call->data, call->priv);
     568        }
     569       
     570        if (call->buffer) {
     571                /*
     572                 * This must be an affirmative answer to IPC_M_DATA_READ
     573                 * or IPC_M_DEBUG/UDEBUG_M_MEM_READ...
     574                 *
     575                 */
     576                uintptr_t dst = IPC_GET_ARG1(call->data);
     577                size_t size = IPC_GET_ARG2(call->data);
     578                int rc = copy_to_uspace((void *) dst, call->buffer, size);
     579                if (rc)
     580                        IPC_SET_RETVAL(call->data, rc);
     581                free(call->buffer);
     582                call->buffer = NULL;
     583        }
     584}
    263585
    264586/** Do basic kernel processing of received call request.
     
    273595static int process_request(answerbox_t *box, call_t *call)
    274596{
    275         int rc = EOK;
    276 
    277         sysipc_ops_t *ops = sysipc_ops_get(call->request_method);
    278         if (ops->request_process)
    279                 rc = ops->request_process(call, box);
    280        
    281         return rc;
     597        if (IPC_GET_IMETHOD(call->data) == IPC_M_CONNECT_TO_ME) {
     598                int phoneid = phone_alloc(TASK);
     599                if (phoneid < 0) {  /* Failed to allocate phone */
     600                        IPC_SET_RETVAL(call->data, ELIMIT);
     601                        ipc_answer(box, call);
     602                        return -1;
     603                }
     604               
     605                IPC_SET_ARG5(call->data, phoneid);
     606        }
     607       
     608        switch (IPC_GET_IMETHOD(call->data)) {
     609        case IPC_M_DEBUG:
     610                return -1;
     611        default:
     612                break;
     613        }
     614       
     615        return 0;
    282616}
    283617
     
    411745{
    412746        call_t *call = get_call(callid);
    413         phone_t *phone;
    414         bool need_old = answer_need_old(call);
    415         bool after_forward = false;
    416         ipc_data_t old;
    417         int rc;
    418 
    419747        if (!call)
    420748                return ENOENT;
    421 
    422         if (need_old)
    423                 old = call->data;
    424        
     749       
     750        call->flags |= IPC_CALL_FORWARDED;
     751       
     752        phone_t *phone;
    425753        if (phone_get(phoneid, &phone) != EOK) {
    426                 rc = ENOENT;
    427                 goto error;
     754                IPC_SET_RETVAL(call->data, EFORWARD);
     755                ipc_answer(&TASK->answerbox, call);
     756                return ENOENT;
    428757        }
    429758       
    430759        if (!method_is_forwardable(IPC_GET_IMETHOD(call->data))) {
    431                 rc = EPERM;
    432                 goto error;
    433         }
    434 
    435         call->flags |= IPC_CALL_FORWARDED;
     760                IPC_SET_RETVAL(call->data, EFORWARD);
     761                ipc_answer(&TASK->answerbox, call);
     762                return EPERM;
     763        }
    436764       
    437765        /*
     
    469797        }
    470798       
    471         rc = ipc_forward(call, phone, &TASK->answerbox, mode);
    472         if (rc != EOK) {
    473                 after_forward = true;
    474                 goto error;
    475         }
    476 
    477         return EOK;
    478 
    479 error:
    480         IPC_SET_RETVAL(call->data, EFORWARD);
    481         (void) answer_preprocess(call, need_old ? &old : NULL);
    482         if (after_forward)
    483                 _ipc_answer_free_call(call, false);
    484         else
    485                 ipc_answer(&TASK->answerbox, call);
    486 
    487         return rc;
     799        return ipc_forward(call, phone, &TASK->answerbox, mode);
    488800}
    489801
  • kernel/generic/src/proc/task.c

    r983cabe8 r3ffd4c3  
    162162        for (i = 0; i < IPC_MAX_PHONES; i++)
    163163                ipc_phone_init(&task->phones[i]);
    164 
    165         spinlock_initialize(&task->active_calls_lock, "active_calls_lock");
    166         list_initialize(&task->active_calls);
    167164       
    168165#ifdef CONFIG_UDEBUG
     
    206203        event_task_init(task);
    207204       
    208         task->answerbox.active = true;
    209 
    210205#ifdef CONFIG_UDEBUG
    211206        /* Init debugging stuff */
     
    213208       
    214209        /* Init kbox stuff */
    215         task->kb.box.active = true;
    216210        task->kb.finished = false;
    217211#endif
     
    219213        if ((ipc_phone_0) &&
    220214            (container_check(ipc_phone_0->task->container, task->container)))
    221                 (void) ipc_phone_connect(&task->phones[0], ipc_phone_0);
     215                ipc_phone_connect(&task->phones[0], ipc_phone_0);
    222216       
    223217        btree_create(&task->futexes);
Note: See TracChangeset for help on using the changeset viewer.