Changeset e8039a86 in mainline


Ignore:
Timestamp:
2012-08-20T23:21:41Z (12 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
0343a1b
Parents:
642dc72
Message:

Separate system IPC logic into dedicated ops structure hooks.

Location:
kernel/generic
Files:
15 edited

Legend:

Unmodified
Added
Removed
  • kernel/generic/include/config.h

    r642dc72 re8039a86  
    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/ipcrsc.h

    r642dc72 re8039a86  
    4040
    4141extern call_t *get_call(sysarg_t);
     42extern int phone_get(sysarg_t, phone_t **);
    4243extern int phone_alloc(task_t *);
    4344extern void phone_connect(int, answerbox_t *);
  • kernel/generic/src/ipc/ipcrsc.c

    r642dc72 re8039a86  
    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.
     
    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
  • kernel/generic/src/ipc/ops/clnestab.c

    r642dc72 re8039a86  
    3434
    3535#include <ipc/sysipc_ops.h>
     36#include <ipc/ipc.h>
     37#include <synch/mutex.h>
     38#include <abi/errno.h>
     39
     40static int request_preprocess(call_t *call, phone_t *phone)
     41{
     42        IPC_SET_ARG5(call->data, (sysarg_t) phone);
     43
     44        return EOK;     
     45}
     46
     47static int answer_preprocess(call_t *answer, ipc_data_t *olddata)
     48{
     49        phone_t *phone = (phone_t *) IPC_GET_ARG5(*olddata);
     50
     51        if (IPC_GET_RETVAL(answer->data) != EOK) {
     52                /*
     53                 * The other party on the cloned phone rejected our request
     54                 * for connection on the protocol level.  We need to break the
     55                 * connection without sending IPC_M_HUNGUP back.
     56                 */
     57                mutex_lock(&phone->lock);
     58                if (phone->state == IPC_PHONE_CONNECTED) {
     59                        irq_spinlock_lock(&phone->callee->lock, true);
     60                        list_remove(&phone->link);
     61                        phone->state = IPC_PHONE_SLAMMED;
     62                        irq_spinlock_unlock(&phone->callee->lock, true);
     63                }
     64                mutex_unlock(&phone->lock);
     65        }
     66       
     67        return EOK;
     68}
    3669
    3770sysipc_ops_t ipc_m_clone_establish_ops = {
    38         .request_preprocess = null_request_preprocess,
     71        .request_preprocess = request_preprocess,
    3972        .request_process = null_request_process,
    40         .answer_preprocess = null_answer_preprocess,
     73        .answer_preprocess = answer_preprocess,
    4174        .answer_process = null_answer_process,
    4275};
  • kernel/generic/src/ipc/ops/conctmeto.c

    r642dc72 re8039a86  
    11/*
     2 * Copyright (c) 2006 Ondrej Palkovsky
    23 * Copyright (c) 2012 Jakub Jermar
    34 * All rights reserved.
     
    3435
    3536#include <ipc/sysipc_ops.h>
     37#include <ipc/ipc.h>
     38#include <ipc/ipcrsc.h>
     39#include <abi/errno.h>
     40#include <arch.h>
    3641
    37 static sysipc_ops_t ipc_m_connect_me_to_ops = {
    38         .request_preprocess = null_request_preprocess,
     42static int request_preprocess(call_t *call, phone_t *phone)
     43{
     44        int newphid = phone_alloc(TASK);
     45
     46        if (newphid < 0)
     47                return ELIMIT;
     48               
     49        /* Set arg5 for server */
     50        IPC_SET_ARG5(call->data, (sysarg_t) &TASK->phones[newphid]);
     51        call->flags |= IPC_CALL_CONN_ME_TO;
     52        call->priv = newphid;
     53
     54        return EOK;
     55}
     56
     57static int answer_preprocess(call_t *answer, ipc_data_t *olddata)
     58{
     59        phone_t *phone = (phone_t *) IPC_GET_ARG5(*olddata);
     60
     61        /* If the user accepted call, connect */
     62        if (IPC_GET_RETVAL(answer->data) == EOK)
     63                ipc_phone_connect(phone, &TASK->answerbox);
     64
     65        return EOK;
     66}
     67
     68
     69sysipc_ops_t ipc_m_connect_me_to_ops = {
     70        .request_preprocess = request_preprocess,
    3971        .request_process = null_request_process,
    40         .answer_preprocess = null_answer_preprocess,
     72        .answer_preprocess = answer_preprocess,
    4173        .answer_process = null_answer_process,
    4274};
    4375
    44 sysipc_ops_t *ipc_m_connect_me_to_ops_p = &ipc_m_connect_me_to_ops;
    45 
    4676/** @}
    4777 */
  • kernel/generic/src/ipc/ops/concttome.c

    r642dc72 re8039a86  
    11/*
     2 * Copyright (c) 2006 Ondrej Palkovsky
    23 * Copyright (c) 2012 Jakub Jermar
    34 * All rights reserved.
     
    3435
    3536#include <ipc/sysipc_ops.h>
     37#include <ipc/ipc.h>
     38#include <ipc/ipcrsc.h>
     39#include <abi/errno.h>
     40#include <arch.h>
     41
     42static int request_process(call_t *call, answerbox_t *box)
     43{
     44        int phoneid = phone_alloc(TASK);
     45
     46        if (phoneid < 0) {  /* Failed to allocate phone */
     47                IPC_SET_RETVAL(call->data, ELIMIT);
     48                ipc_answer(box, call);
     49                return -1;
     50        }
     51               
     52        IPC_SET_ARG5(call->data, phoneid);
     53       
     54        return EOK;
     55}
     56
     57static int answer_preprocess(call_t *answer, ipc_data_t *olddata)
     58{
     59        int phoneid = (int) IPC_GET_ARG5(*olddata);
     60
     61        if (IPC_GET_RETVAL(answer->data) != EOK) {
     62                /* The connection was not accepted */
     63                int phoneid = (int) IPC_GET_ARG5(*olddata);
     64       
     65                phone_dealloc(phoneid);
     66        } else {
     67                /* The connection was accepted */
     68                phone_connect(phoneid, &answer->sender->answerbox);
     69                /* Set 'phone hash' as arg5 of response */
     70                IPC_SET_ARG5(answer->data, (sysarg_t) &TASK->phones[phoneid]);
     71        }
     72
     73        return EOK;
     74}
     75
    3676
    3777sysipc_ops_t ipc_m_connect_to_me_ops = {
    3878        .request_preprocess = null_request_preprocess,
    39         .request_process = null_request_process,
    40         .answer_preprocess = null_answer_preprocess,
     79        .request_process = request_process,
     80        .answer_preprocess = answer_preprocess,
    4181        .answer_process = null_answer_process,
    4282};
  • kernel/generic/src/ipc/ops/connclone.c

    r642dc72 re8039a86  
    3434
    3535#include <ipc/sysipc_ops.h>
     36#include <ipc/ipc.h>
     37#include <ipc/ipcrsc.h>
     38#include <synch/mutex.h>
     39#include <abi/errno.h>
     40#include <arch.h>
     41
     42static void phones_lock(phone_t *p1, phone_t *p2)
     43{
     44        if (p1 < p2) {
     45                mutex_lock(&p1->lock);
     46                mutex_lock(&p2->lock);
     47        } else if (p1 > p2) {
     48                mutex_lock(&p2->lock);
     49                mutex_lock(&p1->lock);
     50        } else
     51                mutex_lock(&p1->lock);
     52}
     53
     54static void phones_unlock(phone_t *p1, phone_t *p2)
     55{
     56        mutex_unlock(&p1->lock);
     57        if (p1 != p2)
     58                mutex_unlock(&p2->lock);
     59}
     60
     61static int request_preprocess(call_t *call, phone_t *phone)
     62{
     63        phone_t *cloned_phone;
     64
     65        if (phone_get(IPC_GET_ARG1(call->data), &cloned_phone) != EOK)
     66                return ENOENT;
     67               
     68        phones_lock(cloned_phone, phone);
     69               
     70        if ((cloned_phone->state != IPC_PHONE_CONNECTED) ||
     71            phone->state != IPC_PHONE_CONNECTED) {
     72                phones_unlock(cloned_phone, phone);
     73                return EINVAL;
     74        }
     75               
     76        /*
     77         * We can be pretty sure now that both tasks exist and we are
     78         * connected to them. As we continue to hold the phone locks,
     79         * we are effectively preventing them from finishing their
     80         * potential cleanup.
     81         *
     82         */
     83        int newphid = phone_alloc(phone->callee->task);
     84        if (newphid < 0) {
     85                phones_unlock(cloned_phone, phone);
     86                return ELIMIT;
     87        }
     88               
     89        ipc_phone_connect(&phone->callee->task->phones[newphid],
     90            cloned_phone->callee);
     91        phones_unlock(cloned_phone, phone);
     92               
     93        /* Set the new phone for the callee. */
     94        IPC_SET_ARG1(call->data, newphid);
     95
     96        return EOK;
     97}
     98
     99static int answer_preprocess(call_t *answer, ipc_data_t *olddata)
     100{
     101        if (IPC_GET_RETVAL(answer->data) != EOK) {
     102                /*
     103                 * The recipient of the cloned phone rejected the offer.
     104                 */
     105                int phoneid = (int) IPC_GET_ARG1(*olddata);
     106                phone_t *phone = &TASK->phones[phoneid];
     107
     108                /*
     109                 * In this case, the connection was established at the request
     110                 * time and therefore we need to slam the phone.  We don't
     111                 * merely hangup as that would result in sending IPC_M_HUNGUP
     112                 * to the third party on the other side of the cloned phone.
     113                 */
     114                mutex_lock(&phone->lock);
     115                if (phone->state == IPC_PHONE_CONNECTED) {
     116                        irq_spinlock_lock(&phone->callee->lock, true);
     117                        list_remove(&phone->link);
     118                        phone->state = IPC_PHONE_SLAMMED;
     119                        irq_spinlock_unlock(&phone->callee->lock, true);
     120                }
     121                mutex_unlock(&phone->lock);
     122        }
     123
     124        return EOK;
     125}
    36126
    37127sysipc_ops_t ipc_m_connection_clone_ops = {
    38         .request_preprocess = null_request_preprocess,
     128        .request_preprocess = request_preprocess,
    39129        .request_process = null_request_process,
    40         .answer_preprocess = null_answer_preprocess,
     130        .answer_preprocess = answer_preprocess,
    41131        .answer_process = null_answer_process,
    42132};
  • kernel/generic/src/ipc/ops/dataread.c

    r642dc72 re8039a86  
    3434
    3535#include <ipc/sysipc_ops.h>
     36#include <ipc/ipc.h>
     37#include <mm/slab.h>
     38#include <abi/errno.h>
     39#include <syscall/copy.h>
     40#include <config.h>
     41
     42static int request_preprocess(call_t *call, phone_t *phone)
     43{
     44        size_t size = IPC_GET_ARG2(call->data);
     45
     46        if (size > DATA_XFER_LIMIT) {
     47                int flags = IPC_GET_ARG3(call->data);
     48
     49                if (flags & IPC_XF_RESTRICT)
     50                        IPC_SET_ARG2(call->data, DATA_XFER_LIMIT);
     51                else
     52                        return ELIMIT;
     53        }
     54
     55        return EOK;
     56}
     57
     58static int answer_preprocess(call_t *answer, ipc_data_t *olddata)
     59{
     60        ASSERT(!answer->buffer);
     61
     62        if (!IPC_GET_RETVAL(answer->data)) {
     63                /* The recipient agreed to send data. */
     64                uintptr_t src = IPC_GET_ARG1(answer->data);
     65                uintptr_t dst = IPC_GET_ARG1(*olddata);
     66                size_t max_size = IPC_GET_ARG2(*olddata);
     67                size_t size = IPC_GET_ARG2(answer->data);
     68                if (size && size <= max_size) {
     69                        /*
     70                         * Copy the destination VA so that this piece of
     71                         * information is not lost.
     72                         */
     73                        IPC_SET_ARG1(answer->data, dst);
     74                               
     75                        answer->buffer = malloc(size, 0);
     76                        int rc = copy_from_uspace(answer->buffer,
     77                            (void *) src, size);
     78                        if (rc) {
     79                                IPC_SET_RETVAL(answer->data, rc);
     80                                free(answer->buffer);
     81                                answer->buffer = NULL;
     82                        }
     83                } else if (!size) {
     84                        IPC_SET_RETVAL(answer->data, EOK);
     85                } else {
     86                        IPC_SET_RETVAL(answer->data, ELIMIT);
     87                }
     88        }
     89
     90        return EOK;
     91}
    3692
    3793sysipc_ops_t ipc_m_data_read_ops = {
    38         .request_preprocess = null_request_preprocess,
     94        .request_preprocess = request_preprocess,
    3995        .request_process = null_request_process,
    40         .answer_preprocess = null_answer_preprocess,
     96        .answer_preprocess = answer_preprocess,
    4197        .answer_process = null_answer_process,
    4298};
  • kernel/generic/src/ipc/ops/datawrite.c

    r642dc72 re8039a86  
    3434
    3535#include <ipc/sysipc_ops.h>
     36#include <ipc/ipc.h>
     37#include <mm/slab.h>
     38#include <abi/errno.h>
     39#include <syscall/copy.h>
     40#include <config.h>
     41
     42static int request_preprocess(call_t *call, phone_t *phone)
     43{
     44        uintptr_t src = IPC_GET_ARG1(call->data);
     45        size_t size = IPC_GET_ARG2(call->data);
     46
     47        if (size > DATA_XFER_LIMIT) {
     48                int flags = IPC_GET_ARG3(call->data);
     49
     50                if (flags & IPC_XF_RESTRICT) {
     51                        size = DATA_XFER_LIMIT;
     52                        IPC_SET_ARG2(call->data, size);
     53                } else
     54                        return ELIMIT;
     55        }
     56
     57        call->buffer = (uint8_t *) malloc(size, 0);
     58        int rc = copy_from_uspace(call->buffer, (void *) src, size);
     59        if (rc != 0) {
     60                free(call->buffer);
     61                return rc;
     62        }
     63               
     64        return EOK;
     65}
     66
     67static int answer_preprocess(call_t *answer, ipc_data_t *olddata)
     68{
     69        ASSERT(answer->buffer);
     70
     71        if (!IPC_GET_RETVAL(answer->data)) {
     72                /* The recipient agreed to receive data. */
     73                uintptr_t dst = (uintptr_t)IPC_GET_ARG1(answer->data);
     74                size_t size = (size_t)IPC_GET_ARG2(answer->data);
     75                size_t max_size = (size_t)IPC_GET_ARG2(*olddata);
     76                       
     77                if (size <= max_size) {
     78                        int rc = copy_to_uspace((void *) dst,
     79                            answer->buffer, size);
     80                        if (rc)
     81                                IPC_SET_RETVAL(answer->data, rc);
     82                } else {
     83                        IPC_SET_RETVAL(answer->data, ELIMIT);
     84                }
     85        }
     86        free(answer->buffer);
     87        answer->buffer = NULL;
     88
     89        return EOK;
     90}
     91
    3692
    3793sysipc_ops_t ipc_m_data_write_ops = {
    38         .request_preprocess = null_request_preprocess,
     94        .request_preprocess = request_preprocess,
    3995        .request_process = null_request_process,
    40         .answer_preprocess = null_answer_preprocess,
     96        .answer_preprocess = answer_preprocess,
    4197        .answer_process = null_answer_process,
    4298};
  • kernel/generic/src/ipc/ops/debug.c

    r642dc72 re8039a86  
    11/*
    2  * Copyright (c) 2012 Jakub Jermar
     2 * Copyright (c) 2008 Jiri Svoboda
    33 * All rights reserved.
    44 *
     
    3434
    3535#include <ipc/sysipc_ops.h>
     36#include <ipc/ipc.h>
     37#include <udebug/udebug_ipc.h>
     38
     39static int request_process(call_t *call, answerbox_t *box)
     40{
     41        return -1;
     42}
    3643
    3744sysipc_ops_t ipc_m_debug_ops = {
     45#ifdef CONFIG_UDEBUG
     46        .request_preprocess = udebug_request_preprocess,
     47#else
    3848        .request_preprocess = null_request_preprocess,
    39         .request_process = null_request_process,
     49#endif
     50        .request_process = request_process,
    4051        .answer_preprocess = null_answer_preprocess,
    4152        .answer_process = null_answer_process,
  • kernel/generic/src/ipc/ops/sharein.c

    r642dc72 re8039a86  
    3434
    3535#include <ipc/sysipc_ops.h>
     36#include <ipc/ipc.h>
     37#include <mm/as.h>
     38#include <synch/spinlock.h>
     39#include <proc/task.h>
     40#include <abi/errno.h>
     41#include <arch.h>
     42
     43static int answer_preprocess(call_t *answer, ipc_data_t *olddata)
     44{
     45        if (!IPC_GET_RETVAL(answer->data)) {
     46                irq_spinlock_lock(&answer->sender->lock, true);
     47                as_t *as = answer->sender->as;
     48                irq_spinlock_unlock(&answer->sender->lock, true);
     49                       
     50                uintptr_t dst_base = (uintptr_t) -1;
     51                int rc = as_area_share(AS, IPC_GET_ARG1(answer->data),
     52                    IPC_GET_ARG1(*olddata), as, IPC_GET_ARG2(answer->data),
     53                    &dst_base, IPC_GET_ARG3(answer->data));
     54                IPC_SET_ARG4(answer->data, dst_base);
     55                IPC_SET_RETVAL(answer->data, rc);
     56        }
     57       
     58        return EOK;
     59}
    3660
    3761sysipc_ops_t ipc_m_share_in_ops = {
    3862        .request_preprocess = null_request_preprocess,
    3963        .request_process = null_request_process,
    40         .answer_preprocess = null_answer_preprocess,
     64        .answer_preprocess = answer_preprocess,
    4165        .answer_process = null_answer_process,
    4266};
  • kernel/generic/src/ipc/ops/shareout.c

    r642dc72 re8039a86  
    3434
    3535#include <ipc/sysipc_ops.h>
     36#include <ipc/ipc.h>
     37#include <mm/as.h>
     38#include <synch/spinlock.h>
     39#include <proc/task.h>
     40#include <syscall/copy.h>
     41#include <abi/errno.h>
     42#include <arch.h>
     43
     44static int request_preprocess(call_t *call, phone_t *phone)
     45{
     46        size_t size = as_area_get_size(IPC_GET_ARG1(call->data));
     47
     48        if (!size)
     49                return EPERM;
     50        IPC_SET_ARG2(call->data, size);
     51
     52        return EOK;
     53}
     54
     55static int answer_preprocess(call_t *answer, ipc_data_t *olddata)
     56{
     57        int rc = EOK;
     58
     59        if (!IPC_GET_RETVAL(answer->data)) {
     60                /* Accepted, handle as_area receipt */
     61
     62                irq_spinlock_lock(&answer->sender->lock, true);
     63                as_t *as = answer->sender->as;
     64                irq_spinlock_unlock(&answer->sender->lock, true);
     65
     66                uintptr_t dst_base = (uintptr_t) -1;
     67                rc = as_area_share(as, IPC_GET_ARG1(*olddata),
     68                    IPC_GET_ARG2(*olddata), AS, IPC_GET_ARG3(*olddata),
     69                    &dst_base, IPC_GET_ARG1(answer->data));
     70                       
     71                if (rc == EOK) {
     72                        rc = copy_to_uspace((void *) IPC_GET_ARG2(answer->data),
     73                            &dst_base, sizeof(dst_base));
     74                }
     75                       
     76                IPC_SET_RETVAL(answer->data, rc);
     77        }
     78
     79        return rc;
     80}
    3681
    3782sysipc_ops_t ipc_m_share_out_ops = {
    38         .request_preprocess = null_request_preprocess,
     83        .request_preprocess = request_preprocess,
    3984        .request_process = null_request_process,
    40         .answer_preprocess = null_answer_preprocess,
     85        .answer_preprocess = answer_preprocess,
    4186        .answer_process = null_answer_process,
    4287};
  • kernel/generic/src/ipc/ops/stchngath.c

    r642dc72 re8039a86  
    3434
    3535#include <ipc/sysipc_ops.h>
     36#include <ipc/ipc.h>
     37#include <ipc/ipcrsc.h>
     38#include <synch/mutex.h>
     39#include <proc/task.h>
     40#include <abi/errno.h>
     41#include <macros.h>
     42
     43static int request_preprocess(call_t *call, phone_t *phone)
     44{
     45        phone_t *sender_phone;
     46        task_t *other_task_s;
     47
     48        if (phone_get(IPC_GET_ARG5(call->data), &sender_phone) != EOK)
     49                return ENOENT;
     50
     51        mutex_lock(&sender_phone->lock);
     52        if (sender_phone->state != IPC_PHONE_CONNECTED) {
     53                mutex_unlock(&sender_phone->lock);
     54                return EINVAL;
     55        }
     56
     57        other_task_s = sender_phone->callee->task;
     58
     59        mutex_unlock(&sender_phone->lock);
     60
     61        /* Remember the third party task hash. */
     62        IPC_SET_ARG5(call->data, (sysarg_t) other_task_s);
     63
     64        return EOK;
     65}
     66
     67static int answer_preprocess(call_t *answer, ipc_data_t *olddata)
     68{
     69        int rc = EOK;
     70
     71        if (!IPC_GET_RETVAL(answer->data)) {
     72                /* The recipient authorized the change of state. */
     73                phone_t *recipient_phone;
     74                task_t *other_task_s;
     75                task_t *other_task_r;
     76
     77                rc = phone_get(IPC_GET_ARG1(answer->data),
     78                    &recipient_phone);
     79                if (rc != EOK) {
     80                        IPC_SET_RETVAL(answer->data, ENOENT);
     81                        return ENOENT;
     82                }
     83
     84                mutex_lock(&recipient_phone->lock);
     85                if (recipient_phone->state != IPC_PHONE_CONNECTED) {
     86                        mutex_unlock(&recipient_phone->lock);
     87                        IPC_SET_RETVAL(answer->data, EINVAL);
     88                        return EINVAL;
     89                }
     90
     91                other_task_r = recipient_phone->callee->task;
     92                other_task_s = (task_t *) IPC_GET_ARG5(*olddata);
     93
     94                /*
     95                 * See if both the sender and the recipient meant the
     96                 * same third party task.
     97                 */
     98                if (other_task_r != other_task_s) {
     99                        IPC_SET_RETVAL(answer->data, EINVAL);
     100                        rc = EINVAL;
     101                } else {
     102                        rc = event_task_notify_5(other_task_r,
     103                            EVENT_TASK_STATE_CHANGE, false,
     104                            IPC_GET_ARG1(*olddata),
     105                            IPC_GET_ARG2(*olddata),
     106                            IPC_GET_ARG3(*olddata),
     107                            LOWER32(olddata->task_id),
     108                            UPPER32(olddata->task_id));
     109                        IPC_SET_RETVAL(answer->data, rc);
     110                }
     111
     112                mutex_unlock(&recipient_phone->lock);
     113        }
     114
     115        return rc;
     116}
    36117
    37118sysipc_ops_t ipc_m_state_change_authorize_ops = {
    38         .request_preprocess = null_request_preprocess,
     119        .request_preprocess = request_preprocess,
    39120        .request_process = null_request_process,
    40         .answer_preprocess = null_answer_preprocess,
     121        .answer_preprocess = answer_preprocess,
    41122        .answer_process = null_answer_process,
    42123};
  • kernel/generic/src/ipc/sysipc.c

    r642dc72 re8039a86  
    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>
    4442#include <ipc/irq.h>
    4543#include <ipc/ipcrsc.h>
     
    4745#include <ipc/kbox.h>
    4846#include <synch/waitq.h>
    49 #include <udebug/udebug_ipc.h>
    5047#include <arch/interrupt.h>
    5148#include <syscall/copy.h>
    5249#include <security/cap.h>
    5350#include <console/console.h>
    54 #include <mm/as.h>
    5551#include <print.h>
    5652#include <macros.h>
    5753
    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 
    6454#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 }
    8255
    8356/** Decide if the interface and method is a system method.
     
    174147}
    175148
    176 static void cleanup_m_connection_clone(call_t *answer, ipc_data_t *olddata)
    177 {
    178         int phoneid = (int) IPC_GET_ARG1(*olddata);
    179         phone_t *phone = &TASK->phones[phoneid];
    180 
    181         /*
    182          * In this case, the connection was established at the request time and
    183          * therefore we need to slam the phone.  We don't merely hangup as that
    184          * would result in sending IPC_M_HUNGUP to the third party on the other
    185          * side of the cloned phone.
    186          */
    187         mutex_lock(&phone->lock);
    188         if (phone->state == IPC_PHONE_CONNECTED) {
    189                 irq_spinlock_lock(&phone->callee->lock, true);
    190                 list_remove(&phone->link);
    191                 phone->state = IPC_PHONE_SLAMMED;
    192                 irq_spinlock_unlock(&phone->callee->lock, true);
    193         }
    194         mutex_unlock(&phone->lock);
    195 }
    196 
    197 static int a_preprocess_m_connection_clone(call_t *answer, ipc_data_t *olddata)
    198 {
    199         if (IPC_GET_RETVAL(answer->data) != EOK) {
    200                 /*
    201                  * The recipient of the cloned phone rejected the offer.
    202                  */
    203                 cleanup_m_connection_clone(answer, olddata);
    204         }
    205 
    206         return EOK;
    207 }
    208 
    209 static int a_preprocess_m_clone_establish(call_t *answer, ipc_data_t *olddata)
    210 {
    211         phone_t *phone = (phone_t *) IPC_GET_ARG5(*olddata);
    212 
    213         if (IPC_GET_RETVAL(answer->data) != EOK) {
    214                 /*
    215                  * The other party on the cloned phone rejected our request
    216                  * for connection on the protocol level.  We need to break the
    217                  * connection without sending IPC_M_HUNGUP back.
    218                  */
    219                 mutex_lock(&phone->lock);
    220                 if (phone->state == IPC_PHONE_CONNECTED) {
    221                         irq_spinlock_lock(&phone->callee->lock, true);
    222                         list_remove(&phone->link);
    223                         phone->state = IPC_PHONE_SLAMMED;
    224                         irq_spinlock_unlock(&phone->callee->lock, true);
    225                 }
    226                 mutex_unlock(&phone->lock);
    227         }
    228        
    229         return EOK;
    230 }
    231 
    232 static void cleanup_m_connect_to_me(call_t *answer, ipc_data_t *olddata)
    233 {
    234         int phoneid = (int) IPC_GET_ARG5(*olddata);
    235        
    236         phone_dealloc(phoneid);
    237 }
    238 
    239 static int a_preprocess_m_connect_to_me(call_t *answer, ipc_data_t *olddata)
    240 {
    241         int phoneid = (int) IPC_GET_ARG5(*olddata);
    242 
    243         if (IPC_GET_RETVAL(answer->data) != EOK) {
    244                 /* The connection was not accepted */
    245                 cleanup_m_connect_to_me(answer, olddata);
    246         } else {
    247                 /* The connection was accepted */
    248                 phone_connect(phoneid, &answer->sender->answerbox);
    249                 /* Set 'phone hash' as arg5 of response */
    250                 IPC_SET_ARG5(answer->data, (sysarg_t) &TASK->phones[phoneid]);
    251         }
    252 
    253         return EOK;
    254 }
    255 
    256 static void cleanup_m_connect_me_to(call_t *answer, ipc_data_t *olddata)
    257 {
    258         /* FIXME: answer->priv phone needs to be deallocated. */
    259 }
    260 
    261 static int a_preprocess_m_connect_me_to(call_t *answer, ipc_data_t *olddata)
    262 {
    263         phone_t *phone = (phone_t *) IPC_GET_ARG5(*olddata);
    264 
    265         /* If the user accepted call, connect */
    266         if (IPC_GET_RETVAL(answer->data) == EOK)
    267                 ipc_phone_connect(phone, &TASK->answerbox);
    268 
    269         return EOK;
    270 }
    271 
    272 static int a_preprocess_m_share_out(call_t *answer, ipc_data_t *olddata)
    273 {
    274         int rc = EOK;
    275 
    276         if (!IPC_GET_RETVAL(answer->data)) {
    277                 /* Accepted, handle as_area receipt */
    278 
    279                 irq_spinlock_lock(&answer->sender->lock, true);
    280                 as_t *as = answer->sender->as;
    281                 irq_spinlock_unlock(&answer->sender->lock, true);
    282 
    283                 uintptr_t dst_base = (uintptr_t) -1;
    284                 rc = as_area_share(as, IPC_GET_ARG1(*olddata),
    285                     IPC_GET_ARG2(*olddata), AS, IPC_GET_ARG3(*olddata),
    286                     &dst_base, IPC_GET_ARG1(answer->data));
    287                        
    288                 if (rc == EOK) {
    289                         rc = copy_to_uspace((void *) IPC_GET_ARG2(answer->data),
    290                             &dst_base, sizeof(dst_base));
    291                 }
    292                        
    293                 IPC_SET_RETVAL(answer->data, rc);
    294         }
    295 
    296         return rc;
    297 }
    298 
    299 static int a_preprocess_m_share_in(call_t *answer, ipc_data_t *olddata)
    300 {
    301         if (!IPC_GET_RETVAL(answer->data)) {
    302                 irq_spinlock_lock(&answer->sender->lock, true);
    303                 as_t *as = answer->sender->as;
    304                 irq_spinlock_unlock(&answer->sender->lock, true);
    305                        
    306                 uintptr_t dst_base = (uintptr_t) -1;
    307                 int rc = as_area_share(AS, IPC_GET_ARG1(answer->data),
    308                     IPC_GET_ARG1(*olddata), as, IPC_GET_ARG2(answer->data),
    309                     &dst_base, IPC_GET_ARG3(answer->data));
    310                 IPC_SET_ARG4(answer->data, dst_base);
    311                 IPC_SET_RETVAL(answer->data, rc);
    312         }
    313        
    314         return EOK;
    315 }
    316 
    317 static int a_preprocess_m_data_read(call_t *answer, ipc_data_t *olddata)
    318 {
    319         ASSERT(!answer->buffer);
    320         if (!IPC_GET_RETVAL(answer->data)) {
    321                 /* The recipient agreed to send data. */
    322                 uintptr_t src = IPC_GET_ARG1(answer->data);
    323                 uintptr_t dst = IPC_GET_ARG1(*olddata);
    324                 size_t max_size = IPC_GET_ARG2(*olddata);
    325                 size_t size = IPC_GET_ARG2(answer->data);
    326                 if (size && size <= max_size) {
    327                         /*
    328                          * Copy the destination VA so that this piece of
    329                          * information is not lost.
    330                          */
    331                         IPC_SET_ARG1(answer->data, dst);
    332                                
    333                         answer->buffer = malloc(size, 0);
    334                         int rc = copy_from_uspace(answer->buffer,
    335                             (void *) src, size);
    336                         if (rc) {
    337                                 IPC_SET_RETVAL(answer->data, rc);
    338                                 free(answer->buffer);
    339                                 answer->buffer = NULL;
    340                         }
    341                 } else if (!size) {
    342                         IPC_SET_RETVAL(answer->data, EOK);
    343                 } else {
    344                         IPC_SET_RETVAL(answer->data, ELIMIT);
    345                 }
    346         }
    347 
    348         return EOK;
    349 }
    350 
    351 static int a_preprocess_m_data_write(call_t *answer, ipc_data_t *olddata)
    352 {
    353         ASSERT(answer->buffer);
    354         if (!IPC_GET_RETVAL(answer->data)) {
    355                 /* The recipient agreed to receive data. */
    356                 uintptr_t dst = (uintptr_t)IPC_GET_ARG1(answer->data);
    357                 size_t size = (size_t)IPC_GET_ARG2(answer->data);
    358                 size_t max_size = (size_t)IPC_GET_ARG2(*olddata);
    359                        
    360                 if (size <= max_size) {
    361                         int rc = copy_to_uspace((void *) dst,
    362                             answer->buffer, size);
    363                         if (rc)
    364                                 IPC_SET_RETVAL(answer->data, rc);
    365                 } else {
    366                         IPC_SET_RETVAL(answer->data, ELIMIT);
    367                 }
    368         }
    369         free(answer->buffer);
    370         answer->buffer = NULL;
    371 
    372         return EOK;
    373 }
    374 
    375 static int
    376 a_preprocess_m_state_change_authorize(call_t *answer, ipc_data_t *olddata)
    377 {
    378         int rc = EOK;
    379 
    380         if (!IPC_GET_RETVAL(answer->data)) {
    381                 /* The recipient authorized the change of state. */
    382                 phone_t *recipient_phone;
    383                 task_t *other_task_s;
    384                 task_t *other_task_r;
    385 
    386                 rc = phone_get(IPC_GET_ARG1(answer->data),
    387                     &recipient_phone);
    388                 if (rc != EOK) {
    389                         IPC_SET_RETVAL(answer->data, ENOENT);
    390                         return ENOENT;
    391                 }
    392 
    393                 mutex_lock(&recipient_phone->lock);
    394                 if (recipient_phone->state != IPC_PHONE_CONNECTED) {
    395                         mutex_unlock(&recipient_phone->lock);
    396                         IPC_SET_RETVAL(answer->data, EINVAL);
    397                         return EINVAL;
    398                 }
    399 
    400                 other_task_r = recipient_phone->callee->task;
    401                 other_task_s = (task_t *) IPC_GET_ARG5(*olddata);
    402 
    403                 /*
    404                  * See if both the sender and the recipient meant the
    405                  * same third party task.
    406                  */
    407                 if (other_task_r != other_task_s) {
    408                         IPC_SET_RETVAL(answer->data, EINVAL);
    409                         rc = EINVAL;
    410                 } else {
    411                         rc = event_task_notify_5(other_task_r,
    412                             EVENT_TASK_STATE_CHANGE, false,
    413                             IPC_GET_ARG1(*olddata),
    414                             IPC_GET_ARG2(*olddata),
    415                             IPC_GET_ARG3(*olddata),
    416                             LOWER32(olddata->task_id),
    417                             UPPER32(olddata->task_id));
    418                         IPC_SET_RETVAL(answer->data, rc);
    419                 }
    420 
    421                 mutex_unlock(&recipient_phone->lock);
    422         }
    423 
    424         return rc;
    425 }
    426 
    427 /** Cleanup additional resources associated with the answer. */
    428 static void cleanup_forgotten(call_t *answer, ipc_data_t *olddata)
    429 {
    430         if (!olddata)
    431                 return;
    432 
    433         switch (IPC_GET_IMETHOD(*olddata)) {
    434         case IPC_M_CONNECTION_CLONE:
    435                 cleanup_m_connection_clone(answer, olddata);
    436                 break;
    437         case IPC_M_CONNECT_TO_ME:
    438                 cleanup_m_connect_to_me(answer, olddata);
    439                 break;
    440         case IPC_M_CONNECT_ME_TO:
    441                 cleanup_m_connect_me_to(answer, olddata);
    442                 break;
    443         default:
    444                 break;
    445         }
    446 }
    447 
    448149/** Interpret process answer as control information.
    449150 *
     
    466167                 */
    467168                spinlock_unlock(&answer->forget_lock);
    468                 cleanup_forgotten(answer, olddata);
     169                /* TODO: cleanup? */
    469170                return rc;
    470171        } else {
     
    496197        }
    497198       
    498         switch (IPC_GET_IMETHOD(*olddata)) {
    499         case IPC_M_CONNECTION_CLONE:
    500                 rc = a_preprocess_m_connection_clone(answer, olddata);
    501                 break;
    502         case IPC_M_CLONE_ESTABLISH:
    503                 rc = a_preprocess_m_clone_establish(answer, olddata);
    504                 break;
    505         case IPC_M_CONNECT_TO_ME:
    506                 rc = a_preprocess_m_connect_to_me(answer, olddata);
    507                 break;
    508         case IPC_M_CONNECT_ME_TO:
    509                 rc = a_preprocess_m_connect_me_to(answer, olddata);
    510                 break;
    511         case IPC_M_SHARE_OUT:
    512                 rc = a_preprocess_m_share_out(answer, olddata);
    513                 break;
    514         case IPC_M_SHARE_IN:
    515                 rc = a_preprocess_m_share_in(answer, olddata);
    516                 break;
    517         case IPC_M_DATA_READ:
    518                 rc = a_preprocess_m_data_read(answer, olddata);
    519                 break;
    520         case IPC_M_DATA_WRITE:
    521                 rc = a_preprocess_m_data_write(answer, olddata);
    522                 break;
    523         case IPC_M_STATE_CHANGE_AUTHORIZE:
    524                 rc = a_preprocess_m_state_change_authorize(answer, olddata);
    525                 break;
    526         default:
    527                 break;
    528         }
     199
     200        sysipc_ops_t *ops = sysipc_ops_get(IPC_GET_IMETHOD(*olddata));
     201        if (ops->answer_preprocess)
     202                rc = ops->answer_preprocess(answer, olddata);
    529203       
    530204        task_release(answer->sender);
    531205
    532206        return rc;
    533 }
    534 
    535 static void phones_lock(phone_t *p1, phone_t *p2)
    536 {
    537         if (p1 < p2) {
    538                 mutex_lock(&p1->lock);
    539                 mutex_lock(&p2->lock);
    540         } else if (p1 > p2) {
    541                 mutex_lock(&p2->lock);
    542                 mutex_lock(&p1->lock);
    543         } else
    544                 mutex_lock(&p1->lock);
    545 }
    546 
    547 static void phones_unlock(phone_t *p1, phone_t *p2)
    548 {
    549         mutex_unlock(&p1->lock);
    550         if (p1 != p2)
    551                 mutex_unlock(&p2->lock);
    552 }
    553 
    554 static int r_preprocess_m_connection_clone(call_t *call, phone_t *phone)
    555 {
    556         phone_t *cloned_phone;
    557 
    558         if (phone_get(IPC_GET_ARG1(call->data), &cloned_phone) != EOK)
    559                 return ENOENT;
    560                
    561         phones_lock(cloned_phone, phone);
    562                
    563         if ((cloned_phone->state != IPC_PHONE_CONNECTED) ||
    564             phone->state != IPC_PHONE_CONNECTED) {
    565                 phones_unlock(cloned_phone, phone);
    566                 return EINVAL;
    567         }
    568                
    569         /*
    570          * We can be pretty sure now that both tasks exist and we are
    571          * connected to them. As we continue to hold the phone locks,
    572          * we are effectively preventing them from finishing their
    573          * potential cleanup.
    574          *
    575          */
    576         int newphid = phone_alloc(phone->callee->task);
    577         if (newphid < 0) {
    578                 phones_unlock(cloned_phone, phone);
    579                 return ELIMIT;
    580         }
    581                
    582         ipc_phone_connect(&phone->callee->task->phones[newphid],
    583             cloned_phone->callee);
    584         phones_unlock(cloned_phone, phone);
    585                
    586         /* Set the new phone for the callee. */
    587         IPC_SET_ARG1(call->data, newphid);
    588 
    589         return EOK;
    590 }
    591 
    592 static int r_preprocess_m_clone_establish(call_t *call, phone_t *phone)
    593 {
    594         IPC_SET_ARG5(call->data, (sysarg_t) phone);
    595 
    596         return EOK;     
    597 }
    598 
    599 static int r_preprocess_m_connect_me_to(call_t *call, phone_t *phone)
    600 {
    601         int newphid = phone_alloc(TASK);
    602 
    603         if (newphid < 0)
    604                 return ELIMIT;
    605                
    606         /* Set arg5 for server */
    607         IPC_SET_ARG5(call->data, (sysarg_t) &TASK->phones[newphid]);
    608         call->flags |= IPC_CALL_CONN_ME_TO;
    609         call->priv = newphid;
    610 
    611         return EOK;
    612 }
    613 
    614 static int r_preprocess_m_share_out(call_t *call, phone_t *phone)
    615 {
    616         size_t size = as_area_get_size(IPC_GET_ARG1(call->data));
    617 
    618         if (!size)
    619                 return EPERM;
    620         IPC_SET_ARG2(call->data, size);
    621 
    622         return EOK;
    623 }
    624 
    625 static int r_preprocess_m_data_read(call_t *call, phone_t *phone)
    626 {
    627         size_t size = IPC_GET_ARG2(call->data);
    628 
    629         if (size > DATA_XFER_LIMIT) {
    630                 int flags = IPC_GET_ARG3(call->data);
    631 
    632                 if (flags & IPC_XF_RESTRICT)
    633                         IPC_SET_ARG2(call->data, DATA_XFER_LIMIT);
    634                 else
    635                         return ELIMIT;
    636         }
    637 
    638         return EOK;
    639 }
    640 
    641 static int r_preprocess_m_data_write(call_t *call, phone_t *phone)
    642 {
    643         uintptr_t src = IPC_GET_ARG1(call->data);
    644         size_t size = IPC_GET_ARG2(call->data);
    645 
    646         if (size > DATA_XFER_LIMIT) {
    647                 int flags = IPC_GET_ARG3(call->data);
    648 
    649                 if (flags & IPC_XF_RESTRICT) {
    650                         size = DATA_XFER_LIMIT;
    651                         IPC_SET_ARG2(call->data, size);
    652                 } else
    653                         return ELIMIT;
    654         }
    655 
    656         call->buffer = (uint8_t *) malloc(size, 0);
    657         int rc = copy_from_uspace(call->buffer, (void *) src, size);
    658         if (rc != 0) {
    659                 free(call->buffer);
    660                 return rc;
    661         }
    662                
    663         return EOK;
    664 }
    665 
    666 static int r_preprocess_m_state_change_authorize(call_t *call, phone_t *phone)
    667 {
    668         phone_t *sender_phone;
    669         task_t *other_task_s;
    670 
    671         if (phone_get(IPC_GET_ARG5(call->data), &sender_phone) != EOK)
    672                 return ENOENT;
    673 
    674         mutex_lock(&sender_phone->lock);
    675         if (sender_phone->state != IPC_PHONE_CONNECTED) {
    676                 mutex_unlock(&sender_phone->lock);
    677                 return EINVAL;
    678         }
    679 
    680         other_task_s = sender_phone->callee->task;
    681 
    682         mutex_unlock(&sender_phone->lock);
    683 
    684         /* Remember the third party task hash. */
    685         IPC_SET_ARG5(call->data, (sysarg_t) other_task_s);
    686 
    687         return EOK;
    688207}
    689208
     
    700219        int rc = EOK;
    701220
    702         switch (IPC_GET_IMETHOD(call->data)) {
    703         case IPC_M_CONNECTION_CLONE:
    704                 rc = r_preprocess_m_connection_clone(call, phone);
    705                 break;
    706         case IPC_M_CLONE_ESTABLISH:
    707                 rc = r_preprocess_m_clone_establish(call, phone);
    708                 break;
    709         case IPC_M_CONNECT_ME_TO:
    710                 rc = r_preprocess_m_connect_me_to(call, phone);
    711                 break;
    712         case IPC_M_SHARE_OUT:
    713                 rc = r_preprocess_m_share_out(call, phone);
    714                 break;
    715         case IPC_M_DATA_READ:
    716                 rc = r_preprocess_m_data_read(call, phone);
    717                 break;
    718         case IPC_M_DATA_WRITE:
    719                 rc = r_preprocess_m_data_write(call, phone);
    720                 break;
    721         case IPC_M_STATE_CHANGE_AUTHORIZE:
    722                 rc = r_preprocess_m_state_change_authorize(call, phone);
    723                 break;
    724 #ifdef CONFIG_UDEBUG
    725         case IPC_M_DEBUG:
    726                 rc = udebug_request_preprocess(call, phone);
    727                 break;
    728 #endif
    729         default:
    730                 break;
    731         }
     221        sysipc_ops_t *ops = sysipc_ops_get(IPC_GET_IMETHOD(call->data));
     222        if (ops->request_preprocess)
     223                rc = ops->request_preprocess(call, phone);
    732224       
    733225        return rc;
     
    772264}
    773265
    774 static int r_process_m_connect_to_me(answerbox_t *box, call_t *call)
    775 {
    776         int phoneid = phone_alloc(TASK);
    777 
    778         if (phoneid < 0) {  /* Failed to allocate phone */
    779                 IPC_SET_RETVAL(call->data, ELIMIT);
    780                 ipc_answer(box, call);
    781                 return -1;
    782         }
    783                
    784         IPC_SET_ARG5(call->data, phoneid);
    785        
    786         return EOK;
    787 }
    788 
    789 static int r_process_m_debug(answerbox_t *box, call_t *call)
    790 {
    791         return -1;
    792 }
    793266
    794267/** Do basic kernel processing of received call request.
     
    805278        int rc = EOK;
    806279
    807         switch (IPC_GET_IMETHOD(call->data)) {
    808         case IPC_M_CONNECT_TO_ME:
    809                 rc = r_process_m_connect_to_me(box, call);
    810                 break;
    811         case IPC_M_DEBUG:
    812                 rc = r_process_m_debug(box, call);
    813                 break;
    814         default:
    815                 break;
    816         }
     280        sysipc_ops_t *ops = sysipc_ops_get(IPC_GET_IMETHOD(call->data));
     281        if (ops->request_process)
     282                rc = ops->request_process(call, box);
    817283       
    818284        return rc;
  • kernel/generic/src/ipc/sysipc_ops.c

    r642dc72 re8039a86  
    9191sysipc_ops_t *sysipc_ops_get(sysarg_t imethod)
    9292{
    93         if (imethod < sizeof(sysipc_ops) / (sizeof(sysipc_ops_t)))
     93        if (imethod < sizeof(sysipc_ops) / (sizeof(sysipc_ops_t *)))
    9494                return sysipc_ops[imethod] ? sysipc_ops[imethod] : &null_ops;
    9595
Note: See TracChangeset for help on using the changeset viewer.