source: mainline/uspace/app/trace/ipcp.c@ eadaeae8

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since eadaeae8 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: 8.8 KB
Line 
1/*
2 * Copyright (c) 2008 Jiri Svoboda
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 trace
30 * @{
31 */
32/** @file
33 */
34
35#include <stdio.h>
36#include <stdlib.h>
37#include <str_error.h>
38#include <inttypes.h>
39#include <adt/hash_table.h>
40#include <abi/ipc/methods.h>
41#include <macros.h>
42#include "ipc_desc.h"
43#include "proto.h"
44#include "trace.h"
45#include "ipcp.h"
46
47typedef struct {
48 cap_phone_handle_t phone_handle;
49 ipc_call_t question;
50 oper_t *oper;
51
52 cap_call_handle_t call_handle;
53
54 ht_link_t link;
55} pending_call_t;
56
57typedef struct {
58 int server;
59 proto_t *proto;
60} connection_t;
61
62#define MAX_PHONE 64
63connection_t connections[MAX_PHONE];
64int have_conn[MAX_PHONE];
65
66static hash_table_t pending_calls;
67
68/*
69 * Pseudo-protocols
70 */
71proto_t *proto_system; /**< Protocol describing system IPC methods. */
72proto_t *proto_unknown; /**< Protocol with no known methods. */
73
74
75static size_t pending_call_key_hash(void *key)
76{
77 cap_call_handle_t *chandle = (cap_call_handle_t *) key;
78 return CAP_HANDLE_RAW(*chandle);
79}
80
81static size_t pending_call_hash(const ht_link_t *item)
82{
83 pending_call_t *hs = hash_table_get_inst(item, pending_call_t, link);
84 return CAP_HANDLE_RAW(hs->call_handle);
85}
86
87static bool pending_call_key_equal(void *key, const ht_link_t *item)
88{
89 cap_call_handle_t *chandle = (cap_call_handle_t *) key;
90 pending_call_t *hs = hash_table_get_inst(item, pending_call_t, link);
91
92 return *chandle == hs->call_handle;
93}
94
95static hash_table_ops_t pending_call_ops = {
96 .hash = pending_call_hash,
97 .key_hash = pending_call_key_hash,
98 .key_equal = pending_call_key_equal,
99 .equal = NULL,
100 .remove_callback = NULL
101};
102
103
104void ipcp_connection_set(cap_phone_handle_t phone, int server, proto_t *proto)
105{
106 // XXX: there is no longer a limit on the number of phones as phones are
107 // now handled using capabilities
108 if (CAP_HANDLE_RAW(phone) < 0 || CAP_HANDLE_RAW(phone) >= MAX_PHONE)
109 return;
110 connections[CAP_HANDLE_RAW(phone)].server = server;
111 connections[CAP_HANDLE_RAW(phone)].proto = proto;
112 have_conn[CAP_HANDLE_RAW(phone)] = 1;
113}
114
115void ipcp_connection_clear(cap_phone_handle_t phone)
116{
117 have_conn[CAP_HANDLE_RAW(phone)] = 0;
118 connections[CAP_HANDLE_RAW(phone)].server = 0;
119 connections[CAP_HANDLE_RAW(phone)].proto = NULL;
120}
121
122static void ipc_m_print(proto_t *proto, sysarg_t method)
123{
124 oper_t *oper;
125
126 /* Try system methods first */
127 oper = proto_get_oper(proto_system, method);
128
129 if (oper == NULL && proto != NULL) {
130 /* Not a system method, try the user protocol. */
131 oper = proto_get_oper(proto, method);
132 }
133
134 if (oper != NULL) {
135 printf("%s (%" PRIun ")", oper->name, method);
136 return;
137 }
138
139 printf("%" PRIun, method);
140}
141
142void ipcp_init(void)
143{
144 val_type_t arg_def[OPER_MAX_ARGS] = {
145 V_INTEGER,
146 V_INTEGER,
147 V_INTEGER,
148 V_INTEGER,
149 V_INTEGER
150 };
151
152 /*
153 * Create a pseudo-protocol 'unknown' that has no known methods.
154 */
155 proto_unknown = proto_new("unknown");
156
157 /*
158 * Create a pseudo-protocol 'system' defining names of system IPC
159 * methods.
160 */
161 proto_system = proto_new("system");
162
163 for (size_t i = 0; i < ipc_methods_len; i++) {
164 oper_t *oper = oper_new(ipc_methods[i].name, OPER_MAX_ARGS,
165 arg_def, V_INTEGER, OPER_MAX_ARGS, arg_def);
166 proto_add_oper(proto_system, ipc_methods[i].number, oper);
167 }
168
169 bool ok = hash_table_create(&pending_calls, 0, 0, &pending_call_ops);
170 assert(ok);
171}
172
173void ipcp_cleanup(void)
174{
175 proto_delete(proto_system);
176 hash_table_destroy(&pending_calls);
177}
178
179void ipcp_call_out(cap_phone_handle_t phandle, ipc_call_t *call,
180 cap_call_handle_t chandle)
181{
182 pending_call_t *pcall;
183 proto_t *proto;
184 oper_t *oper;
185 sysarg_t *args;
186 int i;
187
188 if (have_conn[CAP_HANDLE_RAW(phandle)])
189 proto = connections[CAP_HANDLE_RAW(phandle)].proto;
190 else
191 proto = NULL;
192
193 args = call->args;
194
195 if ((display_mask & DM_IPC) != 0) {
196 printf("Call ID: %p, phone: %p, proto: %s, method: ",
197 chandle, phandle, (proto ? proto->name : "n/a"));
198 ipc_m_print(proto, IPC_GET_IMETHOD(*call));
199 printf(" args: (%" PRIun ", %" PRIun ", %" PRIun ", "
200 "%" PRIun ", %" PRIun ")\n",
201 args[1], args[2], args[3], args[4], args[5]);
202 }
203
204
205 if ((display_mask & DM_USER) != 0) {
206
207 if (proto != NULL) {
208 oper = proto_get_oper(proto, IPC_GET_IMETHOD(*call));
209 } else {
210 oper = NULL;
211 }
212
213 if (oper != NULL) {
214
215 printf("%s(%p).%s", (proto ? proto->name : "n/a"),
216 phandle, (oper ? oper->name : "unknown"));
217
218 putchar('(');
219 for (i = 1; i <= oper->argc; ++i) {
220 if (i > 1) printf(", ");
221 val_print(args[i], oper->arg_type[i - 1]);
222 }
223 putchar(')');
224
225 if (oper->rv_type == V_VOID && oper->respc == 0) {
226 /*
227 * No response data (typically the task will
228 * not be interested in the response).
229 * We will not display response.
230 */
231 putchar('.');
232 }
233
234 putchar('\n');
235 }
236 } else {
237 oper = NULL;
238 }
239
240 /* Store call in hash table for response matching */
241
242 pcall = malloc(sizeof(pending_call_t));
243 pcall->phone_handle = phandle;
244 pcall->question = *call;
245 pcall->call_handle = chandle;
246 pcall->oper = oper;
247
248 hash_table_insert(&pending_calls, &pcall->link);
249}
250
251static void parse_answer(cap_call_handle_t call_handle, pending_call_t *pcall,
252 ipc_call_t *answer)
253{
254 cap_phone_handle_t phone;
255 sysarg_t method;
256 sysarg_t service;
257 errno_t retval;
258 proto_t *proto;
259 cap_phone_handle_t cphone;
260
261 sysarg_t *resp;
262 oper_t *oper;
263 int i;
264
265 phone = pcall->phone_handle;
266 method = IPC_GET_IMETHOD(pcall->question);
267 retval = IPC_GET_RETVAL(*answer);
268
269 resp = answer->args;
270
271 if ((display_mask & DM_IPC) != 0) {
272 printf("Response to %p: retval=%s, args = (%" PRIun ", "
273 "%" PRIun ", %" PRIun ", %" PRIun ", %" PRIun ")\n",
274 call_handle, str_error_name(retval), IPC_GET_ARG1(*answer),
275 IPC_GET_ARG2(*answer), IPC_GET_ARG3(*answer),
276 IPC_GET_ARG4(*answer), IPC_GET_ARG5(*answer));
277 }
278
279 if ((display_mask & DM_USER) != 0) {
280 oper = pcall->oper;
281
282 if ((oper != NULL) &&
283 ((oper->rv_type != V_VOID) || (oper->respc > 0))) {
284 printf("->");
285
286 if (oper->rv_type != V_VOID) {
287 putchar(' ');
288 val_print((sysarg_t) retval, oper->rv_type);
289 }
290
291 if (oper->respc > 0) {
292 putchar(' ');
293 putchar('(');
294 for (i = 1; i <= oper->respc; ++i) {
295 if (i > 1)
296 printf(", ");
297 val_print(resp[i], oper->resp_type[i - 1]);
298 }
299 putchar(')');
300 }
301
302 putchar('\n');
303 }
304 }
305
306 if ((phone == PHONE_NS) && (method == IPC_M_CONNECT_ME_TO) &&
307 (retval == 0)) {
308 /* Connected to a service (through NS) */
309 service = IPC_GET_ARG2(pcall->question);
310 proto = proto_get_by_srv(service);
311 if (proto == NULL)
312 proto = proto_unknown;
313
314 cphone = (cap_phone_handle_t) IPC_GET_ARG5(*answer);
315 if ((display_mask & DM_SYSTEM) != 0) {
316 printf("Registering connection (phone %p, protocol: %s)\n", cphone,
317 proto->name);
318 }
319
320 ipcp_connection_set(cphone, 0, proto);
321 }
322}
323
324void ipcp_call_in(ipc_call_t *call, cap_call_handle_t chandle)
325{
326 ht_link_t *item;
327 pending_call_t *pcall;
328
329 if ((call->flags & IPC_CALL_ANSWERED) == 0) {
330 /* Not a response */
331 if ((display_mask & DM_IPC) != 0) {
332 printf("Not a response (handle %p)\n", chandle);
333 }
334 return;
335 }
336
337 item = hash_table_find(&pending_calls, &chandle);
338 if (item == NULL)
339 return; /* No matching question found */
340
341 /*
342 * Response matched to question.
343 */
344
345 pcall = hash_table_get_inst(item, pending_call_t, link);
346 hash_table_remove(&pending_calls, &chandle);
347
348 parse_answer(chandle, pcall, call);
349 free(pcall);
350}
351
352void ipcp_hangup(cap_phone_handle_t phone, errno_t rc)
353{
354 if ((display_mask & DM_SYSTEM) != 0) {
355 printf("Hang up phone %p -> %s\n", phone, str_error_name(rc));
356 ipcp_connection_clear(phone);
357 }
358}
359
360/** @}
361 */
Note: See TracBrowser for help on using the repository browser.