Changeset 91b60499 in mainline for kernel/generic/src/ipc/ipcrsc.c


Ignore:
Timestamp:
2017-09-30T06:29:42Z (7 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
300f4c4
Parents:
d076f16 (diff), 6636fb19 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge support for capabilities from lp:~jakub/helenos/caps

This commit introduces capabilities as task-local names for references to kernel
objects. Kernel objects are reference-counted wrappers for a select group of
objects allocated in and by the kernel that can be made accessible to userspace
in a controlled way via integer handles.

So far, a kernel object encapsulates either an irq_t or a phone_t.

Support for the former lead to the removal of kernel-assigned devnos and
unsecure deregistration of IRQs in which a random task was able to unregister
some other task's IRQ.

File:
1 edited

Legend:

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

    rd076f16 r91b60499  
    3939 *
    4040 * The pattern of usage of the resources is:
    41  * - allocate empty phone slot, connect | deallocate slot
     41 * - allocate empty phone capability slot, connect | deallocate slot
    4242 * - disconnect connected phone (some messages might be on the fly)
    4343 * - find phone in slot and send a message using phone
     
    5353 *   atomic on all platforms)
    5454 *
    55  * - To find an empty phone slot, the TASK must be locked
     55 * - To find an empty phone capability slot, the TASK must be locked
    5656 * - To answer a message, the answerbox must be locked
    5757 * - The locking of phone and answerbox is done at the ipc_ level.
     
    7777 *
    7878 * *** Connect_to_me ***
    79  * The caller sends IPC_M_CONNECT_TO_ME. 
     79 * The caller sends IPC_M_CONNECT_TO_ME.
    8080 * The server receives an automatically opened phoneid. If it accepts
    81  * (RETVAL=0), it can use the phoneid immediately.
    82  * Possible race condition can arise, when the client receives messages from new
    83  * connection before getting response for connect_to_me message. Userspace
    84  * should implement handshake protocol that would control it.
     81 * (RETVAL=0), it can use the phoneid immediately.  Possible race condition can
     82 * arise, when the client receives messages from new connection before getting
     83 * response for connect_to_me message. Userspace should implement handshake
     84 * protocol that would control it.
    8585 *
    8686 * Phone hangup
     
    8989 * - The phone is disconnected (no more messages can be sent over this phone),
    9090 *   all in-progress messages are correctly handled. The answerbox receives
    91  *   IPC_M_PHONE_HUNGUP call from the phone that hung up. When all async
    92  *   calls are answered, the phone is deallocated.
     91 *   IPC_M_PHONE_HUNGUP call from the phone that hung up. When all async calls
     92 *   are answered, the phone is deallocated.
    9393 *
    9494 * *** The answerbox hangs up (ipc_answer(EHANGUP))
    95  * - The phone is disconnected. EHANGUP response code is sent
    96  *   to the calling task. All new calls through this phone
    97  *   get a EHUNGUP error code, the task is expected to
    98  *   send an sys_ipc_hangup after cleaning up its internal structures.
     95 * - The phone is disconnected. EHANGUP response code is sent to the calling
     96 *   task. All new calls through this phone get a EHUNGUP error code, the task
     97 *   is expected to send an sys_ipc_hangup after cleaning up its internal
     98 *   structures.
     99 *
    99100 *
    100101 * Call forwarding
    101102 *
    102  * The call can be forwarded, so that the answer to call is passed directly
    103  * to the original sender. However, this poses special problems regarding
    104  * routing of hangup messages.
     103 * The call can be forwarded, so that the answer to call is passed directly to
     104 * the original sender. However, this poses special problems regarding routing
     105 * of hangup messages.
    105106 *
    106107 * sys_ipc_hangup -> IPC_M_PHONE_HUNGUP
     
    133134#include <assert.h>
    134135#include <abi/errno.h>
     136#include <cap/cap.h>
     137#include <mm/slab.h>
    135138
    136139/** Find call_t * in call table according to callid.
     
    138141 * @todo Some speedup (hash table?)
    139142 *
    140  * @param callid Userspace hash of the call. Currently it is the call
    141  *               structure kernel address.
    142  *
    143  * @return NULL on not found, otherwise pointer to the call
    144  *         structure.
     143 * @param callid Userspace hash of the call. Currently it is the call structure
     144 *               kernel address.
     145 *
     146 * @return NULL on not found, otherwise pointer to the call structure.
    145147 *
    146148 */
     
    162164}
    163165
    164 /** Get phone from the current task by ID.
    165  *
    166  * @param phoneid Phone ID.
    167  * @param phone   Place to store pointer to phone.
    168  *
    169  * @return EOK on success, EINVAL if ID is invalid.
    170  *
    171  */
    172 int phone_get(sysarg_t phoneid, phone_t **phone)
    173 {
    174         if (phoneid >= IPC_MAX_PHONES)
    175                 return EINVAL;
    176        
    177         *phone = &TASK->phones[phoneid];
    178         return EOK;
    179 }
    180 
    181 /** Allocate new phone slot in the specified task.
    182  *
    183  * @param task Task for which to allocate a new phone.
    184  *
    185  * @return New phone handle or -1 if the phone handle limit is
    186  *         exceeded.
    187  *
    188  */
    189 int phone_alloc(task_t *task)
    190 {
    191         irq_spinlock_lock(&task->lock, true);
    192        
    193         size_t i;
    194         for (i = 0; i < IPC_MAX_PHONES; i++) {
    195                 phone_t *phone = &task->phones[i];
    196 
    197                 if ((phone->state == IPC_PHONE_HUNGUP) &&
    198                     (atomic_get(&phone->active_calls) == 0))
    199                         phone->state = IPC_PHONE_FREE;
     166static bool phone_reclaim(kobject_t *kobj)
     167{
     168        bool gc = false;
     169
     170        mutex_lock(&kobj->phone->lock);
     171        if (kobj->phone->state == IPC_PHONE_HUNGUP &&
     172            atomic_get(&kobj->phone->active_calls) == 0)
     173                gc = true;
     174        mutex_unlock(&kobj->phone->lock);
     175
     176        return gc;
     177}
     178
     179static void phone_destroy(void *arg)
     180{
     181        phone_t *phone = (phone_t *) arg;
     182        slab_free(phone_slab, phone);
     183}
     184
     185static kobject_ops_t phone_kobject_ops = {
     186        .reclaim = phone_reclaim,
     187        .destroy = phone_destroy
     188};
     189
     190
     191/** Allocate new phone in the specified task.
     192 *
     193 * @param task  Task for which to allocate a new phone.
     194 *
     195 * @return  New phone capability handle.
     196 * @return  Negative error code if a new capability cannot be allocated.
     197 */
     198cap_handle_t phone_alloc(task_t *task)
     199{
     200        cap_handle_t handle = cap_alloc(task);
     201        if (handle >= 0) {
     202                phone_t *phone = slab_alloc(phone_slab, FRAME_ATOMIC);
     203                if (!phone) {
     204                        cap_free(TASK, handle);
     205                        return ENOMEM;
     206                }
     207                kobject_t *kobject = malloc(sizeof(kobject_t), FRAME_ATOMIC);
     208                if (!kobject) {
     209                        cap_free(TASK, handle);
     210                        slab_free(phone_slab, phone);
     211                        return ENOMEM;
     212                }
     213
     214                ipc_phone_init(phone, task);
     215                phone->state = IPC_PHONE_CONNECTING;
     216
     217                kobject_initialize(kobject, KOBJECT_TYPE_PHONE, phone,
     218                    &phone_kobject_ops);
     219                phone->kobject = kobject;
    200220               
    201                 if (phone->state == IPC_PHONE_FREE) {
    202                         phone->state = IPC_PHONE_CONNECTING;
    203                         break;
    204                 }
     221                cap_publish(task, handle, kobject);
    205222        }
    206223       
    207         irq_spinlock_unlock(&task->lock, true);
    208        
    209         if (i == IPC_MAX_PHONES)
    210                 return -1;
    211        
    212         return i;
    213 }
    214 
    215 /** Mark a phone structure free.
    216  *
    217  * @param phone Phone structure to be marked free.
    218  *
    219  */
    220 static void phone_deallocp(phone_t *phone)
    221 {
    222         assert(phone->state == IPC_PHONE_CONNECTING);
    223        
    224         /* Atomic operation */
    225         phone->state = IPC_PHONE_FREE;
     224        return handle;
    226225}
    227226
     
    230229 * All already sent messages will be correctly processed.
    231230 *
    232  * @param phoneid Phone handle of the phone to be freed.
    233  *
    234  */
    235 void phone_dealloc(int phoneid)
    236 {
    237         phone_deallocp(&TASK->phones[phoneid]);
     231 * @param handle Phone capability handle of the phone to be freed.
     232 *
     233 */
     234void phone_dealloc(cap_handle_t handle)
     235{
     236        kobject_t *kobj = cap_unpublish(TASK, handle, KOBJECT_TYPE_PHONE);
     237        if (!kobj)
     238                return;
     239       
     240        assert(kobj->phone);
     241        assert(kobj->phone->state == IPC_PHONE_CONNECTING);
     242       
     243        kobject_put(kobj);
     244        cap_free(TASK, handle);
    238245}
    239246
    240247/** Connect phone to a given answerbox.
    241248 *
    242  * @param phoneid Phone handle to be connected.
    243  * @param box     Answerbox to which to connect the phone handle.
     249 * @param handle  Capability handle of the phone to be connected.
     250 * @param box     Answerbox to which to connect the phone.
    244251 * @return        True if the phone was connected, false otherwise.
    245  *
    246  * The procedure _enforces_ that the user first marks the phone
    247  * busy (e.g. via phone_alloc) and then connects the phone, otherwise
    248  * race condition may appear.
    249  *
    250  */
    251 bool phone_connect(int phoneid, answerbox_t *box)
    252 {
    253         phone_t *phone = &TASK->phones[phoneid];
    254        
    255         assert(phone->state == IPC_PHONE_CONNECTING);
    256         return ipc_phone_connect(phone, box);
     252 */
     253bool phone_connect(cap_handle_t handle, answerbox_t *box)
     254{
     255        kobject_t *phone_obj = kobject_get(TASK, handle, KOBJECT_TYPE_PHONE);
     256        if (!phone_obj)
     257                return false;
     258       
     259        assert(phone_obj->phone->state == IPC_PHONE_CONNECTING);
     260       
     261        /* Hand over phone_obj reference to the answerbox */
     262        return ipc_phone_connect(phone_obj->phone, box);
    257263}
    258264
Note: See TracChangeset for help on using the changeset viewer.