source: mainline/kernel/generic/src/ipc/ipcrsc.c@ 7473807

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 7473807 was eadaeae8, checked in by Jakub Jermar <jakub@…>, 7 years ago

Make capability handles type-safe

Define distinct pointer types for the handles of the supported
capability types and use them instead of integer handles. This makes it
virtually impossible to pass a non-handle or a handle of different type
instead of the proper handle. Also turn cap_handle_t into an "untyped"
capability handle that can be assigned to and from the "typed" handles.

This commit also fixes a bug in msim-con driver, which wrongly used the
IRQ number instead of the IRQ capability handle to unregister the IRQ.

This commit also fixes the wrong use of the capability handle instead
of error code in libusbhost.

  • Property mode set to 100644
File size: 6.9 KB
Line 
1/*
2 * Copyright (c) 2006 Ondrej Palkovsky
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup genericipc
30 * @{
31 */
32/** @file
33 */
34
35/* IPC resources management
36 *
37 * The goal of this source code is to properly manage IPC resources and allow
38 * straight and clean clean-up procedure upon task termination.
39 *
40 * The pattern of usage of the resources is:
41 * - allocate a capability and phone kernel object (do not publish yet),
42 * connect to the answerbox, and finally publish the capability
43 * - disconnect connected phone (some messages might be on the fly)
44 * - find phone capability and send a message using phone
45 * - answer message to phone
46 * - hangup phone (the caller has hung up)
47 * - hangup phone (the answerbox is exiting)
48 *
49 * Locking strategy
50 *
51 * - To use a phone, disconnect a phone etc., the phone must be first locked and
52 * then checked that it is connected
53 * - To connect an allocated phone it need not be locked (assigning pointer is
54 * atomic on all platforms)
55 *
56 * - To answer a message, the answerbox must be locked
57 * - The locking of phone and answerbox is done at the ipc_ level.
58 * It is perfectly correct to pass unconnected phone to these functions and
59 * proper reply will be generated.
60 *
61 * Locking order
62 *
63 * - first phone, then answerbox
64 * + Easy locking on calls
65 * - Very hard traversing list of phones when disconnecting because the phones
66 * may disconnect during traversal of list of connected phones. The only
67 * possibility is try_lock with restart of list traversal.
68 *
69 * Destroying is less frequent, this approach is taken.
70 *
71 * Phone call
72 *
73 * *** Connect_me_to ***
74 * The caller sends IPC_M_CONNECT_ME_TO to an answerbox. The server receives
75 * 'phoneid' of the connecting phone as an ARG5. If it answers with RETVAL=EOK,
76 * the phone call is accepted, otherwise it is refused.
77 *
78 * *** Connect_to_me ***
79 * The caller sends IPC_M_CONNECT_TO_ME.
80 * The server receives an automatically opened phoneid. If it accepts
81 * (RETVAL=EOK), 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.
85 *
86 * Phone hangup
87 *
88 * *** The caller hangs up (sys_ipc_hangup) ***
89 * - The phone is disconnected (no more messages can be sent over this phone),
90 * 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 calls
92 * are answered, the phone is deallocated.
93 *
94 * *** The answerbox hangs up (ipc_answer(EHANGUP))
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 call sys_ipc_hangup after cleaning up its internal
98 * structures.
99 *
100 *
101 * Call forwarding
102 *
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.
106 *
107 * sys_ipc_hangup -> IPC_M_PHONE_HUNGUP
108 * - this message CANNOT be forwarded
109 *
110 * EHANGUP during forward
111 * - The *forwarding* phone will be closed, EFORWARD is sent to receiver.
112 *
113 * EHANGUP, ENOENT during forward
114 * - EFORWARD is sent to the receiver, ipc_forward returns error code EFORWARD
115 *
116 * Cleanup strategy
117 *
118 * 1) Disconnect all our phones ('ipc_phone_hangup').
119 *
120 * 2) Disconnect all phones connected to answerbox.
121 *
122 * 3) Answer all messages in 'calls' and 'dispatched_calls' queues with
123 * appropriate error code (EHANGUP, EFORWARD).
124 *
125 * 4) Wait for all async answers to arrive and dispose of them.
126 *
127 */
128
129#include <synch/spinlock.h>
130#include <ipc/ipc.h>
131#include <arch.h>
132#include <proc/task.h>
133#include <ipc/ipcrsc.h>
134#include <assert.h>
135#include <abi/errno.h>
136#include <cap/cap.h>
137#include <mm/slab.h>
138
139static void phone_destroy(void *arg)
140{
141 phone_t *phone = (phone_t *) arg;
142 slab_free(phone_cache, phone);
143}
144
145static kobject_ops_t phone_kobject_ops = {
146 .destroy = phone_destroy
147};
148
149
150/** Allocate new phone in the specified task.
151 *
152 * @param[in] task Task for which to allocate a new phone.
153 * @param[in] publish If true, the new capability will be published.
154 * @param[out] phandle New phone capability handle.
155 * @param[out] kobject New phone kobject.
156 *
157 * @return An error code if a new capability cannot be allocated.
158 */
159errno_t phone_alloc(task_t *task, bool publish, cap_phone_handle_t *phandle,
160 kobject_t **kobject)
161{
162 cap_handle_t handle;
163 errno_t rc = cap_alloc(task, &handle);
164 if (rc == EOK) {
165 phone_t *phone = slab_alloc(phone_cache, FRAME_ATOMIC);
166 if (!phone) {
167 cap_free(TASK, handle);
168 return ENOMEM;
169 }
170 kobject_t *kobj = malloc(sizeof(kobject_t), FRAME_ATOMIC);
171 if (!kobj) {
172 cap_free(TASK, handle);
173 slab_free(phone_cache, phone);
174 return ENOMEM;
175 }
176
177 ipc_phone_init(phone, task);
178 phone->state = IPC_PHONE_CONNECTING;
179
180 kobject_initialize(kobj, KOBJECT_TYPE_PHONE, phone,
181 &phone_kobject_ops);
182 phone->kobject = kobj;
183
184 if (publish)
185 cap_publish(task, handle, kobj);
186
187 *phandle = handle;
188 if (kobject)
189 *kobject = kobj;
190 }
191 return rc;
192}
193
194/** Free slot from a disconnected phone.
195 *
196 * All already sent messages will be correctly processed.
197 *
198 * @param handle Phone capability handle of the phone to be freed.
199 *
200 */
201void phone_dealloc(cap_phone_handle_t handle)
202{
203 kobject_t *kobj = cap_unpublish(TASK, handle, KOBJECT_TYPE_PHONE);
204 if (!kobj)
205 return;
206
207 kobject_put(kobj);
208 cap_free(TASK, handle);
209}
210
211/** @}
212 */
Note: See TracBrowser for help on using the repository browser.