source: mainline/generic/src/ipc/sysipc.c@ 23d22eb

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 23d22eb was 4e49572, checked in by Ondrej Palkovsky <ondrap@…>, 20 years ago

Added debugger to AMD64.
Added automatic debugging of AS if it is not rewritten with zero.
Did small changes to IPC infrastructure.

  • Property mode set to 100644
File size: 11.2 KB
RevLine 
[2d5a54f3]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#include <arch.h>
30#include <proc/task.h>
31
32#include <errno.h>
33#include <mm/page.h>
34#include <memstr.h>
35#include <debug.h>
36#include <ipc/ipc.h>
37#include <ipc/sysipc.h>
[4e49572]38#include <ipc/ipcrsc.h>
[37c57f2]39
40
[2d5a54f3]41#include <print.h>
[37c57f2]42#include <arch.h>
43#include <proc/thread.h>
[2d5a54f3]44
45/* TODO: multi-threaded connect-to-me can cause race condition
46 * on phone, add counter + thread_kill??
47 *
48 */
49
[2ba7810]50/** Return true if the method is a system method */
51static inline int is_system_method(__native method)
52{
53 if (method <= IPC_M_LAST_SYSTEM)
54 return 1;
55 return 0;
56}
57
58/** Return true if the message with this method is forwardable
59 *
60 * - some system messages may be forwarded, for some of them
61 * it is useless
62 */
63static inline int is_forwardable(__native method)
64{
65 return 1;
66}
67
[2d5a54f3]68/****************************************************/
69/* Functions that preprocess answer before sending
70 * it to the recepient
71 */
72
73/** Return true if the caller (ipc_answer) should save
74 * the old call contents and call answer_preprocess
75 */
76static inline int answer_will_preprocess(call_t *call)
77{
78 if (IPC_GET_METHOD(call->data) == IPC_M_CONNECTTOME)
79 return 1;
[37c57f2]80 if (IPC_GET_METHOD(call->data) == IPC_M_CONNECTMETO)
81 return 1;
[2d5a54f3]82 return 0;
83}
84
85/** Interpret process answer as control information */
[2ba7810]86static inline void answer_preprocess(call_t *answer, ipc_data_t *olddata)
[2d5a54f3]87{
88 int phoneid;
89
[2ba7810]90 if (IPC_GET_METHOD(*olddata) == IPC_M_CONNECTTOME) {
91 phoneid = IPC_GET_ARG3(*olddata);
[2d5a54f3]92 if (IPC_GET_RETVAL(answer->data)) {
93 /* The connection was not accepted */
94 phone_dealloc(phoneid);
[2ba7810]95 } else {
96 /* The connection was accepted */
97 phone_connect(phoneid,&answer->sender->answerbox);
[2d5a54f3]98 }
[37c57f2]99 } else if (IPC_GET_METHOD(*olddata) == IPC_M_CONNECTMETO) {
100 /* If the users accepted call, connect */
101 if (!IPC_GET_RETVAL(answer->data)) {
102 ipc_phone_connect((phone_t *)IPC_GET_ARG3(*olddata),
103 &TASK->answerbox);
104 }
[2d5a54f3]105 }
106}
107
108/****************************************************/
109/* Functions called to process received call/answer
110 * before passing to uspace
111 */
112
113/** Do basic kernel processing of received call answer */
114static int process_answer(answerbox_t *box,call_t *call)
115{
116 return 0;
117}
118
119/** Do basic kernel processing of received call request
120 *
121 * @return 0 - the call should be passed to userspace, 1 - ignore call
122 */
123static int process_request(answerbox_t *box,call_t *call)
124{
125 int phoneid;
126
127 if (IPC_GET_METHOD(call->data) == IPC_M_CONNECTTOME) {
[2ba7810]128 phoneid = phone_alloc();
[2d5a54f3]129 if (phoneid < 0) { /* Failed to allocate phone */
130 IPC_SET_RETVAL(call->data, ELIMIT);
131 ipc_answer(box,call);
132 return -1;
133 }
134 IPC_SET_ARG3(call->data, phoneid);
135 }
136 return 0;
137}
138
139/** Send a call over IPC, wait for reply, return to user
140 *
141 * @return Call identification, returns -1 on fatal error,
142 -2 on 'Too many async request, handle answers first
143 */
144__native sys_ipc_call_sync_fast(__native phoneid, __native method,
145 __native arg1, __native *data)
146{
147 call_t call;
148 phone_t *phone;
149
[2ba7810]150 if (is_system_method(method))
151 return EPERM;
[2d5a54f3]152
[4e49572]153 phone = get_phone_and_lock(phoneid);
154 if (!phone)
155 return ENOENT;
156
[2d5a54f3]157 ipc_call_init(&call);
158 IPC_SET_METHOD(call.data, method);
159 IPC_SET_ARG1(call.data, arg1);
160
161 ipc_call_sync(phone, &call);
162
163 copy_to_uspace(data, &call.data, sizeof(call.data));
164
165 return 0;
166}
167
168/** Synchronous IPC call allowing to send whole message */
169__native sys_ipc_call_sync(__native phoneid, __native *question,
170 __native *reply)
171{
172 call_t call;
173 phone_t *phone;
174
175 ipc_call_init(&call);
176 copy_from_uspace(&call.data, question, sizeof(call.data));
[2ba7810]177
178 if (is_system_method(IPC_GET_METHOD(call.data)))
179 return EPERM;
[2d5a54f3]180
[4e49572]181 phone = get_phone_and_lock(phoneid);
182 if (!phone)
183 return ENOENT;
184
[2d5a54f3]185 ipc_call_sync(phone, &call);
186
187 copy_to_uspace(reply, &call.data, sizeof(call.data));
188
189 return 0;
190}
191
192/** Check that the task did not exceed allowed limit
193 *
194 * @return 0 - Limit OK, -1 - limit exceeded
195 */
196static int check_call_limit(void)
197{
198 if (atomic_preinc(&TASK->active_calls) > IPC_MAX_ASYNC_CALLS) {
199 atomic_dec(&TASK->active_calls);
200 return -1;
201 }
202 return 0;
203}
204
205/** Send an asynchronous call over ipc
206 *
207 * @return Call identification, returns -1 on fatal error,
208 -2 on 'Too many async request, handle answers first
209 */
210__native sys_ipc_call_async_fast(__native phoneid, __native method,
211 __native arg1, __native arg2)
212{
213 call_t *call;
214 phone_t *phone;
215
[2ba7810]216 if (is_system_method(method))
217 return IPC_CALLRET_FATAL;
218
[2d5a54f3]219 if (check_call_limit())
220 return IPC_CALLRET_TEMPORARY;
221
[4e49572]222 phone = get_phone_and_lock(phoneid);
223 if (!phone)
224 return IPC_CALLRET_FATAL;
225
[2d5a54f3]226 call = ipc_call_alloc();
227 IPC_SET_METHOD(call->data, method);
228 IPC_SET_ARG1(call->data, arg1);
229 IPC_SET_ARG2(call->data, arg2);
230
231 ipc_call(phone, call);
232
233 return (__native) call;
234}
235
236/** Synchronous IPC call allowing to send whole message
237 *
238 * @return The same as sys_ipc_call_async
239 */
240__native sys_ipc_call_async(__native phoneid, __native *data)
241{
242 call_t *call;
243 phone_t *phone;
244
245 if (check_call_limit())
246 return IPC_CALLRET_TEMPORARY;
247
[4e49572]248 phone = get_phone_and_lock(phoneid);
249 if (!phone)
250 return IPC_CALLRET_FATAL;
251
[2d5a54f3]252 call = ipc_call_alloc();
253 copy_from_uspace(&call->data, data, sizeof(call->data));
[2ba7810]254
255 if (is_system_method(IPC_GET_METHOD(call->data))) {
256 ipc_call_free(call);
257 return EPERM;
258 }
[2d5a54f3]259
260 ipc_call(phone, call);
261
262 return (__native) call;
263}
264
[2ba7810]265/** Forward received call to another destination
266 *
267 * The arg1 and arg2 are changed in the forwarded message
[37c57f2]268 *
269 * Warning: If implementing non-fast version, make sure that
270 * arg3 is not rewritten for certain system IPC
[2ba7810]271 */
272__native sys_ipc_forward_fast(__native callid, __native phoneid,
273 __native method, __native arg1)
274{
275 call_t *call;
276 phone_t *phone;
277
278 call = get_call(callid);
279 if (!call)
280 return ENOENT;
281
[4e49572]282 phone = get_phone_and_lock(phoneid);
[2ba7810]283 if (!phone) {
284 IPC_SET_RETVAL(call->data, EFORWARD);
285 ipc_answer(&TASK->answerbox, call);
286 return ENOENT;
287 }
288
289 if (!is_forwardable(IPC_GET_METHOD(call->data))) {
290 IPC_SET_RETVAL(call->data, EFORWARD);
291 ipc_answer(&TASK->answerbox, call);
292 return EPERM;
293 }
294
295 /* Userspace is not allowed to change method of system methods
296 * on forward, allow changing ARG1 and ARG2 by means of method and arg1
297 */
298 if (is_system_method(IPC_GET_METHOD(call->data))) {
299 IPC_SET_ARG1(call->data, method);
300 IPC_SET_ARG2(call->data, arg1);
301 } else {
302 IPC_SET_METHOD(call->data, method);
303 IPC_SET_ARG1(call->data, arg1);
304 }
305
306 ipc_forward(call, phone->callee, &TASK->answerbox);
307
308 return 0;
309}
310
[2d5a54f3]311/** Send IPC answer */
312__native sys_ipc_answer_fast(__native callid, __native retval,
313 __native arg1, __native arg2)
314{
315 call_t *call;
[2ba7810]316 ipc_data_t saved_data;
[2d5a54f3]317 int preprocess = 0;
318
[2ba7810]319 call = get_call(callid);
320 if (!call)
321 return ENOENT;
[2d5a54f3]322
323 if (answer_will_preprocess(call)) {
[2ba7810]324 memcpy(&saved_data, &call->data, sizeof(call->data));
[2d5a54f3]325 preprocess = 1;
326 }
327
328 IPC_SET_RETVAL(call->data, retval);
329 IPC_SET_ARG1(call->data, arg1);
330 IPC_SET_ARG2(call->data, arg2);
[2ba7810]331
[2d5a54f3]332 if (preprocess)
[2ba7810]333 answer_preprocess(call, &saved_data);
[2d5a54f3]334
335 ipc_answer(&TASK->answerbox, call);
336 return 0;
337}
338
339/** Send IPC answer */
340inline __native sys_ipc_answer(__native callid, __native *data)
341{
342 call_t *call;
[2ba7810]343 ipc_data_t saved_data;
[2d5a54f3]344 int preprocess = 0;
345
[2ba7810]346 call = get_call(callid);
347 if (!call)
348 return ENOENT;
[2d5a54f3]349
350 if (answer_will_preprocess(call)) {
[2ba7810]351 memcpy(&saved_data, &call->data, sizeof(call->data));
[2d5a54f3]352 preprocess = 1;
353 }
354 copy_from_uspace(&call->data, data, sizeof(call->data));
355
356 if (preprocess)
[2ba7810]357 answer_preprocess(call, &saved_data);
[2d5a54f3]358
359 ipc_answer(&TASK->answerbox, call);
360
361 return 0;
362}
363
364/** Ask the other side of connection to do 'callback' connection
365 *
366 * @return 0 if no error, error otherwise
367 */
368__native sys_ipc_connect_to_me(__native phoneid, __native arg1,
369 __native arg2, task_id_t *taskid)
370{
371 call_t call;
372 phone_t *phone;
373
374 ipc_call_init(&call);
375 IPC_SET_METHOD(call.data, IPC_M_CONNECTTOME);
376 IPC_SET_ARG1(call.data, arg1);
377 IPC_SET_ARG2(call.data, arg2);
378
[4e49572]379 phone = get_phone_and_lock(phoneid);
380 if (!phone)
381 return ENOENT;
382
[2d5a54f3]383 ipc_call_sync(phone, &call);
384
385 if (!IPC_GET_RETVAL(call.data) && taskid)
386 copy_to_uspace(taskid,
387 &phone->callee->task->taskid,
388 sizeof(TASK->taskid));
[37c57f2]389
[2d5a54f3]390 return IPC_GET_RETVAL(call.data);
391}
392
[2ba7810]393/** Ask target process to connect me somewhere
394 *
395 * @return phoneid - on success, error otherwise
396 */
397__native sys_ipc_connect_me_to(__native phoneid, __native arg1,
398 __native arg2)
399{
400 call_t call;
401 phone_t *phone;
[37c57f2]402 int newphid;
[2ba7810]403
[4e49572]404 phone = get_phone_and_lock(phoneid);
[2ba7810]405 if (!phone)
406 return ENOENT;
407
[37c57f2]408 newphid = phone_alloc();
409 if (newphid < 0)
410 return ELIMIT;
411
[2ba7810]412 ipc_call_init(&call);
413 IPC_SET_METHOD(call.data, IPC_M_CONNECTMETO);
414 IPC_SET_ARG1(call.data, arg1);
415 IPC_SET_ARG2(call.data, arg2);
[37c57f2]416 IPC_SET_ARG3(call.data, (__native)&TASK->phones[newphid]);
[2ba7810]417
418 ipc_call_sync(phone, &call);
[37c57f2]419
420 if (IPC_GET_RETVAL(call.data)) { /* Connection failed */
421 phone_dealloc(newphid);
422 return IPC_GET_RETVAL(call.data);
[2ba7810]423 }
424
[37c57f2]425 return newphid;
[2ba7810]426}
427
[2d5a54f3]428/** Wait for incoming ipc call or answer
429 *
430 * Generic function - can serve either as inkernel or userspace call
431 * - inside kernel does probably unnecessary copying of data (TODO)
432 *
433 * @param result
434 * @param taskid
435 * @param flags
436 * @return Callid, if callid & 1, then the call is answer
437 */
438inline __native sys_ipc_wait_for_call(ipc_data_t *calldata,
439 task_id_t *taskid,
440 __native flags)
441
442{
443 call_t *call;
444
445restart:
446 call = ipc_wait_for_call(&TASK->answerbox, flags);
447
448 if (call->flags & IPC_CALL_ANSWERED) {
449 if (process_answer(&TASK->answerbox, call))
450 goto restart;
451
452 copy_to_uspace(calldata, &call->data, sizeof(call->data));
453 atomic_dec(&TASK->active_calls);
454 ASSERT(! (call->flags & IPC_CALL_STATIC_ALLOC));
455 ipc_call_free(call);
456
457 return ((__native)call) | IPC_CALLID_ANSWERED;
458 }
459 if (process_request(&TASK->answerbox, call))
460 goto restart;
461 copy_to_uspace(calldata, &call->data, sizeof(call->data));
462 copy_to_uspace(taskid, (void *)&TASK->taskid, sizeof(TASK->taskid));
463 return (__native)call;
464}
465
Note: See TracBrowser for help on using the repository browser.