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


Ignore:
Files:
13 added
13 edited

Legend:

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

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

    r3ffd4c3 r983cabe8  
    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 \
    259270        generic/src/ipc/ipcrsc.c \
    260271        generic/src/ipc/irq.c \
  • kernel/generic/include/config.h

    r3ffd4c3 r983cabe8  
    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)
    4955
    5056#ifndef __ASM__
  • kernel/generic/include/ipc/ipc.h

    r3ffd4c3 r983cabe8  
    7272typedef struct answerbox {
    7373        IRQ_SPINLOCK_DECLARE(lock);
     74
     75        /** Answerbox is active until it enters cleanup. */
     76        bool active;
    7477       
    7578        struct task *task;
     
    106109
    107110typedef struct {
    108         link_t link;
     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;
    109120       
    110121        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;
    111139       
    112         /** Identification of the caller. */
     140        /**
     141         * Identification of the caller.
     142         * Valid only when the call is not forgotten.
     143         */
    113144        struct task *sender;
     145       
     146        /** Phone which was used to send the call. */
     147        phone_t *caller_phone;
    114148       
    115149        /** Private data to internal IPC. */
     
    118152        /** Data passed from/to userspace. */
    119153        ipc_data_t data;
    120        
     154
     155        /** Method as it was sent in the request. */
     156        sysarg_t request_method;
     157
    121158        /** Buffer for IPC_M_DATA_WRITE and IPC_M_DATA_READ. */
    122159        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;
    130160} call_t;
    131161
     
    141171extern int ipc_forward(call_t *, phone_t *, answerbox_t *, unsigned int);
    142172extern void ipc_answer(answerbox_t *, call_t *);
     173extern void _ipc_answer_free_call(call_t *, bool);
    143174
    144175extern void ipc_phone_init(phone_t *);
    145 extern void ipc_phone_connect(phone_t *, answerbox_t *);
     176extern bool ipc_phone_connect(phone_t *, answerbox_t *);
    146177extern int ipc_phone_hangup(phone_t *);
    147178
     
    151182extern void ipc_backsend_err(phone_t *, call_t *, sysarg_t);
    152183extern void ipc_answerbox_slam_phones(answerbox_t *, bool);
    153 extern void ipc_cleanup_call_list(list_t *);
     184extern void ipc_cleanup_call_list(answerbox_t *, list_t *);
    154185
    155186extern void ipc_print_task(task_id_t);
  • kernel/generic/include/ipc/ipcrsc.h

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

    r3ffd4c3 r983cabe8  
    9191       
    9292        /* IPC stuff */
    93         answerbox_t answerbox;  /**< Communication endpoint */
     93
     94        /** Receiving communication endpoint */
     95        answerbox_t answerbox;
     96
     97        /** Sending communication endpoints */
    9498        phone_t phones[IPC_MAX_PHONES];
    95         stats_ipc_t ipc_info;   /**< IPC statistics */
     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
    96109        event_t events[EVENT_TASK_END - EVENT_END];
     110
     111        /** IPC statistics */
     112        stats_ipc_t ipc_info;
    97113       
    98114#ifdef CONFIG_UDEBUG
  • kernel/generic/src/ipc/event.c

    r3ffd4c3 r983cabe8  
    163163                                call->data.task_id = TASK ? TASK->taskid : 0;
    164164                               
    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);
     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);
    170174                               
    171175                                if (mask)
  • kernel/generic/src/ipc/ipc.c

    r3ffd4c3 r983cabe8  
    4545#include <ipc/kbox.h>
    4646#include <ipc/event.h>
     47#include <ipc/sysipc_ops.h>
     48#include <ipc/sysipc_priv.h>
    4749#include <errno.h>
    4850#include <mm/slab.h>
     
    7173{
    7274        memsetb(call, sizeof(*call), 0);
     75        spinlock_initialize(&call->forget_lock, "forget_lock");
     76        call->active = false;
     77        call->forget = false;
    7378        call->sender = TASK;
    7479        call->buffer = NULL;
     
    132137 * @param phone Initialized phone structure.
    133138 * @param box   Initialized answerbox structure.
    134  *
    135  */
    136 void ipc_phone_connect(phone_t *phone, answerbox_t *box)
    137 {
     139 * @return      True if the phone was connected, false otherwise.
     140 */
     141bool ipc_phone_connect(phone_t *phone, answerbox_t *box)
     142{
     143        bool active;
     144
    138145        mutex_lock(&phone->lock);
    139        
    140         phone->state = IPC_PHONE_CONNECTED;
    141         phone->callee = box;
    142        
    143146        irq_spinlock_lock(&box->lock, true);
    144         list_append(&phone->link, &box->connected_phones);
     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
    145155        irq_spinlock_unlock(&box->lock, true);
    146        
    147156        mutex_unlock(&phone->lock);
     157
     158        return active;
    148159}
    149160
     
    167178 *
    168179 */
    169 static 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        
     180void _ipc_answer_free_call(call_t *call, bool selflocked)
     181{
    174182        /* Count sent answer */
    175183        irq_spinlock_lock(&TASK->lock, true);
    176184        TASK->ipc_info.answer_sent++;
    177185        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);
     203                }
     204        }
     205        spinlock_unlock(&call->forget_lock);
     206
     207        answerbox_t *callerbox = &call->sender->answerbox;
     208        bool do_lock = ((!selflocked) || (callerbox != &TASK->answerbox));
    178209       
    179210        call->flags |= IPC_CALL_ANSWERED;
    180211       
    181         if (call->flags & IPC_CALL_FORWARDED) {
    182                 if (call->caller_phone) {
    183                         /* Demasquerade the caller phone. */
    184                         call->data.phone = call->caller_phone;
    185                 }
    186         }
    187 
    188212        call->data.task_id = TASK->taskid;
    189213       
     
    191215                irq_spinlock_lock(&callerbox->lock, true);
    192216       
    193         list_append(&call->link, &callerbox->answers);
     217        list_append(&call->ab_link, &callerbox->answers);
    194218       
    195219        if (do_lock)
     
    209233        /* Remove from active box */
    210234        irq_spinlock_lock(&box->lock, true);
    211         list_remove(&call->link);
     235        list_remove(&call->ab_link);
    212236        irq_spinlock_unlock(&box->lock, true);
    213237       
     
    228252void ipc_backsend_err(phone_t *phone, call_t *call, sysarg_t err)
    229253{
     254        call->caller_phone = phone;
    230255        call->data.phone = phone;
    231256        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
    232262        IPC_SET_RETVAL(call->data, err);
    233263        _ipc_answer_free_call(call, false);
     
    250280        if (!(call->flags & IPC_CALL_FORWARDED)) {
    251281                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
    252290                call->data.phone = phone;
    253291                call->data.task_id = TASK->taskid;
     
    255293       
    256294        irq_spinlock_lock(&box->lock, true);
    257         list_append(&call->link, &box->calls);
     295        list_append(&call->ab_link, &box->calls);
    258296        irq_spinlock_unlock(&box->lock, true);
    259297       
     
    275313        if (phone->state != IPC_PHONE_CONNECTED) {
    276314                mutex_unlock(&phone->lock);
    277                 if (call->flags & IPC_CALL_FORWARDED) {
    278                         IPC_SET_RETVAL(call->data, EFORWARD);
    279                         _ipc_answer_free_call(call, false);
    280                 } else {
     315                if (!(call->flags & IPC_CALL_FORWARDED)) {
    281316                        if (phone->state == IPC_PHONE_HUNGUP)
    282317                                ipc_backsend_err(phone, call, EHANGUP);
     
    356391        TASK->ipc_info.forwarded++;
    357392        irq_spinlock_pass(&TASK->lock, &oldbox->lock);
    358         list_remove(&call->link);
     393        list_remove(&call->ab_link);
    359394        irq_spinlock_unlock(&oldbox->lock, true);
    360395       
    361396        if (mode & IPC_FF_ROUTE_FROM_ME) {
    362                 if (!call->caller_phone)
    363                         call->caller_phone = call->data.phone;
    364397                call->data.phone = newphone;
    365398                call->data.task_id = TASK->taskid;
     
    406439               
    407440                request = list_get_instance(list_first(&box->irq_notifs),
    408                     call_t, link);
    409                 list_remove(&request->link);
     441                    call_t, ab_link);
     442                list_remove(&request->ab_link);
    410443               
    411444                irq_spinlock_unlock(&box->irq_lock, false);
     
    416449                /* Handle asynchronous answers */
    417450                request = list_get_instance(list_first(&box->answers),
    418                     call_t, link);
    419                 list_remove(&request->link);
    420                 atomic_dec(&request->data.phone->active_calls);
     451                    call_t, ab_link);
     452                list_remove(&request->ab_link);
     453                atomic_dec(&request->caller_phone->active_calls);
    421454        } else if (!list_empty(&box->calls)) {
    422455                /* Count received call */
     
    425458                /* Handle requests */
    426459                request = list_get_instance(list_first(&box->calls),
    427                     call_t, link);
    428                 list_remove(&request->link);
     460                    call_t, ab_link);
     461                list_remove(&request->ab_link);
    429462               
    430463                /* Append request to dispatch queue */
    431                 list_append(&request->link, &box->dispatched_calls);
     464                list_append(&request->ab_link, &box->dispatched_calls);
    432465        } else {
    433466                /* This can happen regularly after ipc_cleanup */
     
    449482/** Answer all calls from list with EHANGUP answer.
    450483 *
     484 * @param box Answerbox with the list.
    451485 * @param lst Head of the list to be cleaned up.
    452  *
    453  */
    454 void ipc_cleanup_call_list(list_t *lst)
    455 {
     486 */
     487void ipc_cleanup_call_list(answerbox_t *box, list_t *lst)
     488{
     489        irq_spinlock_lock(&box->lock, true);
    456490        while (!list_empty(lst)) {
    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                
     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;
    463499                IPC_SET_RETVAL(call->data, EHANGUP);
     500                answer_preprocess(call, &old);
    464501                _ipc_answer_free_call(call, true);
    465         }
     502
     503                irq_spinlock_lock(&box->lock, true);
     504        }
     505        irq_spinlock_unlock(&box->lock, true);
    466506}
    467507
     
    529569}
    530570
     571static void ipc_forget_all_active_calls(void)
     572{
     573        call_t *call;
     574
     575restart:
     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. */
     620static void ipc_wait_for_all_answered_calls(void)
     621{
     622        call_t *call;
     623        size_t i;
     624
     625restart:
     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
    531684/** Clean up all IPC communication of the current task.
    532685 *
     
    537690void ipc_cleanup(void)
    538691{
     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
    539702        /* Disconnect all our phones ('ipc_phone_hangup') */
    540         size_t i;
    541         for (i = 0; i < IPC_MAX_PHONES; i++)
     703        for (size_t i = 0; i < IPC_MAX_PHONES; i++)
    542704                ipc_phone_hangup(&TASK->phones[i]);
    543705       
     
    557719       
    558720        /* Answer all messages in 'calls' and 'dispatched_calls' queues */
    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         }
     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();
    606727}
    607728
     
    615736        ipc_answerbox_slab = slab_cache_create("answerbox_t",
    616737            sizeof(answerbox_t), 0, NULL, NULL, 0);
     738}
     739
     740
     741static 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        }
    617772}
    618773
     
    688843       
    689844        printf(" --- incomming calls ---\n");
    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        
     845        ipc_print_call_list(&task->answerbox.calls);
    709846        printf(" --- dispatched calls ---\n");
    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        
     847        ipc_print_call_list(&task->answerbox.dispatched_calls);
    729848        printf(" --- incoming answers ---\n");
    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         }
     849        ipc_print_call_list(&task->answerbox.answers);
    748850       
    749851        irq_spinlock_unlock(&task->answerbox.lock, false);
  • kernel/generic/src/ipc/ipcrsc.c

    r3ffd4c3 r983cabe8  
    132132#include <ipc/ipcrsc.h>
    133133#include <debug.h>
     134#include <abi/errno.h>
    134135
    135136/** Find call_t * in call table according to callid.
     
    151152       
    152153        list_foreach(TASK->answerbox.dispatched_calls, lst) {
    153                 call_t *call = list_get_instance(lst, call_t, link);
     154                call_t *call = list_get_instance(lst, call_t, ab_link);
    154155                if ((sysarg_t) call == callid) {
    155156                        result = call;
     
    160161        irq_spinlock_unlock(&TASK->answerbox.lock, true);
    161162        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 */
     173int 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;
    162180}
    163181
     
    223241 * @param phoneid Phone handle to be connected.
    224242 * @param box     Answerbox to which to connect the phone handle.
     243 * @return        True if the phone was connected, false otherwise.
    225244 *
    226245 * The procedure _enforces_ that the user first marks the phone
     
    229248 *
    230249 */
    231 void phone_connect(int phoneid, answerbox_t *box)
     250bool phone_connect(int phoneid, answerbox_t *box)
    232251{
    233252        phone_t *phone = &TASK->phones[phoneid];
    234253       
    235254        ASSERT(phone->state == IPC_PHONE_CONNECTING);
    236         ipc_phone_connect(phone, box);
     255        return ipc_phone_connect(phone, box);
    237256}
    238257
  • kernel/generic/src/ipc/irq.c

    r3ffd4c3 r983cabe8  
    510510{
    511511        irq_spinlock_lock(&irq->notif_cfg.answerbox->irq_lock, false);
    512         list_append(&call->link, &irq->notif_cfg.answerbox->irq_notifs);
     512        list_append(&call->ab_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

    r3ffd4c3 r983cabe8  
    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        /*
    5058         * Only hold kb.cleanup_lock while setting kb.finished -
    5159         * this is enough.
     
    8896       
    8997        /* Answer all messages in 'calls' and 'dispatched_calls' queues. */
    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);
     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);
    94100}
    95101
     
    236242       
    237243        /* Connect the newly allocated phone to the kbox */
    238         ipc_phone_connect(&TASK->phones[newphid], &task->kb.box);
     244        (void) ipc_phone_connect(&TASK->phones[newphid], &task->kb.box);
    239245       
    240246        if (task->kb.thread != NULL) {
  • kernel/generic/src/ipc/sysipc.c

    r3ffd4c3 r983cabe8  
    3434
    3535#include <arch.h>
    36 #include <proc/task.h>
    37 #include <proc/thread.h>
    3836#include <errno.h>
    3937#include <memstr.h>
    40 #include <debug.h>
    4138#include <ipc/ipc.h>
    4239#include <abi/ipc/methods.h>
    4340#include <ipc/sysipc.h>
     41#include <ipc/sysipc_ops.h>
     42#include <ipc/sysipc_priv.h>
    4443#include <ipc/irq.h>
    4544#include <ipc/ipcrsc.h>
     
    4746#include <ipc/kbox.h>
    4847#include <synch/waitq.h>
    49 #include <udebug/udebug_ipc.h>
    5048#include <arch/interrupt.h>
    5149#include <syscall/copy.h>
    5250#include <security/cap.h>
    5351#include <console/console.h>
    54 #include <mm/as.h>
    5552#include <print.h>
    5653#include <macros.h>
    5754
    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 
    6455#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  */
    74 static 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 }
    8256
    8357/** Decide if the interface and method is a system method.
     
    181155 * @param olddata Saved data of the request.
    182156 *
    183  * @return Return 0 on success or an error code.
    184  *
    185  */
    186 static inline int answer_preprocess(call_t *answer, ipc_data_t *olddata)
    187 {
     157 * @return Return EOK on success or a negative error code.
     158 *
     159 */
     160int 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.
     169                 */
     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
    188200        if ((native_t) IPC_GET_RETVAL(answer->data) == EHANGUP) {
    189                 /* In case of forward, hangup the forwared phone,
    190                  * not the originator
    191                  */
    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;
     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);
    197208                }
    198                 irq_spinlock_unlock(&TASK->answerbox.lock, true);
    199                 mutex_unlock(&answer->data.phone->lock);
     209                mutex_unlock(&phone->lock);
    200210        }
    201211       
    202212        if (!olddata)
    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 
    397 static 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 
    409 static void phones_unlock(phone_t *p1, phone_t *p2)
    410 {
    411         mutex_unlock(&p1->lock);
    412         if (p1 != p2)
    413                 mutex_unlock(&p2->lock);
     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;
    414220}
    415221
     
    424230static int request_preprocess(call_t *call, phone_t *phone)
    425231{
    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;
     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;
    546241}
    547242
     
    561256                IPC_SET_RETVAL(call->data, EFORWARD);
    562257       
    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 }
     258        sysipc_ops_t *ops = sysipc_ops_get(call->request_method);
     259        if (ops->answer_process)
     260                (void) ops->answer_process(call);
     261}
     262
    585263
    586264/** Do basic kernel processing of received call request.
     
    595273static int process_request(answerbox_t *box, call_t *call)
    596274{
    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;
     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;
    616282}
    617283
     
    745411{
    746412        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
    747419        if (!call)
    748420                return ENOENT;
    749        
     421
     422        if (need_old)
     423                old = call->data;
     424       
     425        if (phone_get(phoneid, &phone) != EOK) {
     426                rc = ENOENT;
     427                goto error;
     428        }
     429       
     430        if (!method_is_forwardable(IPC_GET_IMETHOD(call->data))) {
     431                rc = EPERM;
     432                goto error;
     433        }
     434
    750435        call->flags |= IPC_CALL_FORWARDED;
    751        
    752         phone_t *phone;
    753         if (phone_get(phoneid, &phone) != EOK) {
    754                 IPC_SET_RETVAL(call->data, EFORWARD);
    755                 ipc_answer(&TASK->answerbox, call);
    756                 return ENOENT;
    757         }
    758        
    759         if (!method_is_forwardable(IPC_GET_IMETHOD(call->data))) {
    760                 IPC_SET_RETVAL(call->data, EFORWARD);
    761                 ipc_answer(&TASK->answerbox, call);
    762                 return EPERM;
    763         }
    764436       
    765437        /*
     
    797469        }
    798470       
    799         return ipc_forward(call, phone, &TASK->answerbox, mode);
     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
     479error:
     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;
    800488}
    801489
  • kernel/generic/src/proc/task.c

    r3ffd4c3 r983cabe8  
    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);
    164167       
    165168#ifdef CONFIG_UDEBUG
     
    203206        event_task_init(task);
    204207       
     208        task->answerbox.active = true;
     209
    205210#ifdef CONFIG_UDEBUG
    206211        /* Init debugging stuff */
     
    208213       
    209214        /* Init kbox stuff */
     215        task->kb.box.active = true;
    210216        task->kb.finished = false;
    211217#endif
     
    213219        if ((ipc_phone_0) &&
    214220            (container_check(ipc_phone_0->task->container, task->container)))
    215                 ipc_phone_connect(&task->phones[0], ipc_phone_0);
     221                (void) ipc_phone_connect(&task->phones[0], ipc_phone_0);
    216222       
    217223        btree_create(&task->futexes);
Note: See TracChangeset for help on using the changeset viewer.