Subversion Repositories HelenOS

Rev

Rev 1040 | Rev 1063 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 1040 Rev 1060
1
/*
1
/*
2
 * Copyright (C) 2006 Ondrej Palkovsky
2
 * Copyright (C) 2006 Ondrej Palkovsky
3
 * All rights reserved.
3
 * All rights reserved.
4
 *
4
 *
5
 * Redistribution and use in source and binary forms, with or without
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
6
 * modification, are permitted provided that the following conditions
7
 * are met:
7
 * are met:
8
 *
8
 *
9
 * - Redistributions of source code must retain the above copyright
9
 * - Redistributions of source code must retain the above copyright
10
 *   notice, this list of conditions and the following disclaimer.
10
 *   notice, this list of conditions and the following disclaimer.
11
 * - Redistributions in binary form must reproduce the above copyright
11
 * - Redistributions in binary form must reproduce the above copyright
12
 *   notice, this list of conditions and the following disclaimer in the
12
 *   notice, this list of conditions and the following disclaimer in the
13
 *   documentation and/or other materials provided with the distribution.
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
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.
15
 *   derived from this software without specific prior written permission.
16
 *
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
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
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
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
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
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
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.
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 */
27
 */
28
 
28
 
29
#include <arch.h>
29
#include <arch.h>
30
#include <proc/task.h>
30
#include <proc/task.h>
31
 
31
 
32
#include <errno.h>
32
#include <errno.h>
33
#include <mm/page.h>
33
#include <mm/page.h>
34
#include <memstr.h>
34
#include <memstr.h>
35
#include <debug.h>
35
#include <debug.h>
36
#include <ipc/ipc.h>
36
#include <ipc/ipc.h>
37
#include <ipc/sysipc.h>
37
#include <ipc/sysipc.h>
-
 
38
 
-
 
39
 
38
#include <print.h>
40
#include <print.h>
-
 
41
#include <arch.h>
-
 
42
#include <proc/thread.h>
39
 
43
 
40
/* TODO: multi-threaded connect-to-me can cause race condition
44
/* TODO: multi-threaded connect-to-me can cause race condition
41
 * on phone, add counter + thread_kill??
45
 * on phone, add counter + thread_kill??
42
 *
46
 *
43
 */
47
 */
44
 
48
 
45
/** Return true if the method is a system method */
49
/** Return true if the method is a system method */
46
static inline int is_system_method(__native method)
50
static inline int is_system_method(__native method)
47
{
51
{
48
    if (method <= IPC_M_LAST_SYSTEM)
52
    if (method <= IPC_M_LAST_SYSTEM)
49
        return 1;
53
        return 1;
50
    return 0;
54
    return 0;
51
}
55
}
52
 
56
 
53
/** Return true if the message with this method is forwardable
57
/** Return true if the message with this method is forwardable
54
 *
58
 *
55
 * - some system messages may be forwarded, for some of them
59
 * - some system messages may be forwarded, for some of them
56
 *   it is useless
60
 *   it is useless
57
 */
61
 */
58
static inline int is_forwardable(__native method)
62
static inline int is_forwardable(__native method)
59
{
63
{
60
    return 1;
64
    return 1;
61
}
65
}
62
 
66
 
63
/** Find call_t * in call table according to callid
67
/** Find call_t * in call table according to callid
64
 *
68
 *
65
 * @return NULL on not found, otherwise pointer to call structure
69
 * @return NULL on not found, otherwise pointer to call structure
66
 */
70
 */
67
static inline call_t * get_call(__native callid)
71
static inline call_t * get_call(__native callid)
68
{
72
{
69
    /* TODO: Traverse list of dispatched calls and find one */
73
    /* TODO: Traverse list of dispatched calls and find one */
70
    /* TODO: locking of call, ripping it from dispatched calls etc.  */
74
    /* TODO: locking of call, ripping it from dispatched calls etc.  */
71
    return (call_t *) callid;
75
    return (call_t *) callid;
72
}
76
}
73
 
77
 
74
/** Return pointer to phone identified by phoneid or NULL if non-existent */
78
/** Return pointer to phone identified by phoneid or NULL if non-existent */
75
static phone_t * get_phone(__native phoneid)
79
static phone_t * get_phone(__native phoneid)
76
{
80
{
77
    phone_t *phone;
81
    phone_t *phone;
78
 
82
 
79
    if (phoneid >= IPC_MAX_PHONES)
83
    if (phoneid >= IPC_MAX_PHONES)
80
        return NULL;
84
        return NULL;
81
 
85
 
82
    phone = &TASK->phones[phoneid];
86
    phone = &TASK->phones[phoneid];
83
    if (!phone->callee)
87
    if (!phone->callee)
84
        return NULL;
88
        return NULL;
85
    return phone;
89
    return phone;
86
}
90
}
87
 
91
 
88
/** Allocate new phone slot in current TASK structure */
92
/** Allocate new phone slot in current TASK structure */
89
static int phone_alloc(void)
93
static int phone_alloc(void)
90
{
94
{
91
    int i;
95
    int i;
92
 
96
 
93
    spinlock_lock(&TASK->lock);
97
    spinlock_lock(&TASK->lock);
94
   
98
   
95
    for (i=0; i < IPC_MAX_PHONES; i++) {
99
    for (i=0; i < IPC_MAX_PHONES; i++) {
96
        if (!TASK->phones[i].busy) {
100
        if (!TASK->phones[i].busy) {
97
            TASK->phones[i].busy = 1;
101
            TASK->phones[i].busy = 1;
98
            break;
102
            break;
99
        }
103
        }
100
    }
104
    }
101
    spinlock_unlock(&TASK->lock);
105
    spinlock_unlock(&TASK->lock);
102
 
106
 
103
    if (i >= IPC_MAX_PHONES)
107
    if (i >= IPC_MAX_PHONES)
104
        return -1;
108
        return -1;
105
    return i;
109
    return i;
106
}
110
}
107
 
111
 
108
/** Disconnect phone */
112
/** Disconnect phone */
109
static void phone_dealloc(int phoneid)
113
static void phone_dealloc(int phoneid)
110
{
114
{
111
    spinlock_lock(&TASK->lock);
115
    spinlock_lock(&TASK->lock);
112
 
116
 
113
    ASSERT(TASK->phones[phoneid].busy);
117
    ASSERT(TASK->phones[phoneid].busy);
114
 
118
 
115
    if (TASK->phones[phoneid].callee)
119
    if (TASK->phones[phoneid].callee)
116
        ipc_phone_destroy(&TASK->phones[phoneid]);
120
        ipc_phone_destroy(&TASK->phones[phoneid]);
117
 
121
 
118
    TASK->phones[phoneid].busy = 0;
122
    TASK->phones[phoneid].busy = 0;
119
    spinlock_unlock(&TASK->lock);
123
    spinlock_unlock(&TASK->lock);
120
}
124
}
121
 
125
 
122
static void phone_connect(int phoneid, answerbox_t *box)
126
static void phone_connect(int phoneid, answerbox_t *box)
123
{
127
{
124
    phone_t *phone = &TASK->phones[phoneid];
128
    phone_t *phone = &TASK->phones[phoneid];
125
   
129
   
126
    ipc_phone_connect(phone, box);
130
    ipc_phone_connect(phone, box);
127
}
131
}
128
 
132
 
129
/****************************************************/
133
/****************************************************/
130
/* Functions that preprocess answer before sending
134
/* Functions that preprocess answer before sending
131
 * it to the recepient
135
 * it to the recepient
132
 */
136
 */
133
 
137
 
134
/** Return true if the caller (ipc_answer) should save
138
/** Return true if the caller (ipc_answer) should save
135
 * the old call contents and call answer_preprocess
139
 * the old call contents and call answer_preprocess
136
 */
140
 */
137
static inline int answer_will_preprocess(call_t *call)
141
static inline int answer_will_preprocess(call_t *call)
138
{
142
{
139
    if (IPC_GET_METHOD(call->data) == IPC_M_CONNECTTOME)
143
    if (IPC_GET_METHOD(call->data) == IPC_M_CONNECTTOME)
140
        return 1;
144
        return 1;
-
 
145
    if (IPC_GET_METHOD(call->data) == IPC_M_CONNECTMETO)
-
 
146
        return 1;
141
    return 0;
147
    return 0;
142
}
148
}
143
 
149
 
144
/** Interpret process answer as control information */
150
/** Interpret process answer as control information */
145
static inline void answer_preprocess(call_t *answer, ipc_data_t *olddata)
151
static inline void answer_preprocess(call_t *answer, ipc_data_t *olddata)
146
{
152
{
147
    int phoneid;
153
    int phoneid;
148
 
154
 
149
    if (IPC_GET_METHOD(*olddata) == IPC_M_CONNECTTOME) {
155
    if (IPC_GET_METHOD(*olddata) == IPC_M_CONNECTTOME) {
150
        phoneid = IPC_GET_ARG3(*olddata);
156
        phoneid = IPC_GET_ARG3(*olddata);
151
        if (IPC_GET_RETVAL(answer->data)) {
157
        if (IPC_GET_RETVAL(answer->data)) {
152
            /* The connection was not accepted */
158
            /* The connection was not accepted */
153
            phone_dealloc(phoneid);
159
            phone_dealloc(phoneid);
154
        } else {
160
        } else {
155
            /* The connection was accepted */
161
            /* The connection was accepted */
156
            phone_connect(phoneid,&answer->sender->answerbox);
162
            phone_connect(phoneid,&answer->sender->answerbox);
157
        }
163
        }
-
 
164
    } else if (IPC_GET_METHOD(*olddata) == IPC_M_CONNECTMETO) {
-
 
165
        /* If the users accepted call, connect */
-
 
166
        if (!IPC_GET_RETVAL(answer->data)) {
-
 
167
            printf("Connecting Phone %P\n",IPC_GET_ARG3(*olddata));
-
 
168
            ipc_phone_connect((phone_t *)IPC_GET_ARG3(*olddata),
-
 
169
                      &TASK->answerbox);
-
 
170
        }
158
    }
171
    }
159
}
172
}
160
 
173
 
161
/****************************************************/
174
/****************************************************/
162
/* Functions called to process received call/answer
175
/* Functions called to process received call/answer
163
 * before passing to uspace
176
 * before passing to uspace
164
 */
177
 */
165
 
178
 
166
/** Do basic kernel processing of received call answer */
179
/** Do basic kernel processing of received call answer */
167
static int process_answer(answerbox_t *box,call_t *call)
180
static int process_answer(answerbox_t *box,call_t *call)
168
{
181
{
169
    return 0;
182
    return 0;
170
}
183
}
171
 
184
 
172
/** Do basic kernel processing of received call request
185
/** Do basic kernel processing of received call request
173
 *
186
 *
174
 * @return 0 - the call should be passed to userspace, 1 - ignore call
187
 * @return 0 - the call should be passed to userspace, 1 - ignore call
175
 */
188
 */
176
static int process_request(answerbox_t *box,call_t *call)
189
static int process_request(answerbox_t *box,call_t *call)
177
{
190
{
178
    int phoneid;
191
    int phoneid;
179
 
192
 
180
    if (IPC_GET_METHOD(call->data) == IPC_M_CONNECTTOME) {
193
    if (IPC_GET_METHOD(call->data) == IPC_M_CONNECTTOME) {
181
        phoneid = phone_alloc();
194
        phoneid = phone_alloc();
182
        if (phoneid < 0) { /* Failed to allocate phone */
195
        if (phoneid < 0) { /* Failed to allocate phone */
183
            IPC_SET_RETVAL(call->data, ELIMIT);
196
            IPC_SET_RETVAL(call->data, ELIMIT);
184
            ipc_answer(box,call);
197
            ipc_answer(box,call);
185
            return -1;
198
            return -1;
186
        }
199
        }
187
        IPC_SET_ARG3(call->data, phoneid);
200
        IPC_SET_ARG3(call->data, phoneid);
188
    }
201
    }
189
    return 0;
202
    return 0;
190
}
203
}
191
 
204
 
192
/** Send a call over IPC, wait for reply, return to user
205
/** Send a call over IPC, wait for reply, return to user
193
 *
206
 *
194
 * @return Call identification, returns -1 on fatal error,
207
 * @return Call identification, returns -1 on fatal error,
195
           -2 on 'Too many async request, handle answers first
208
           -2 on 'Too many async request, handle answers first
196
 */
209
 */
197
__native sys_ipc_call_sync_fast(__native phoneid, __native method,
210
__native sys_ipc_call_sync_fast(__native phoneid, __native method,
198
                __native arg1, __native *data)
211
                __native arg1, __native *data)
199
{
212
{
200
    call_t call;
213
    call_t call;
201
    phone_t *phone;
214
    phone_t *phone;
202
 
215
 
203
    phone = get_phone(phoneid);
216
    phone = get_phone(phoneid);
204
    if (!phone)
217
    if (!phone)
205
        return ENOENT;
218
        return ENOENT;
206
 
219
 
207
    if (is_system_method(method))
220
    if (is_system_method(method))
208
        return EPERM;
221
        return EPERM;
209
 
222
 
210
    ipc_call_init(&call);
223
    ipc_call_init(&call);
211
    IPC_SET_METHOD(call.data, method);
224
    IPC_SET_METHOD(call.data, method);
212
    IPC_SET_ARG1(call.data, arg1);
225
    IPC_SET_ARG1(call.data, arg1);
213
   
226
   
214
    ipc_call_sync(phone, &call);
227
    ipc_call_sync(phone, &call);
215
 
228
 
216
    copy_to_uspace(data, &call.data, sizeof(call.data));
229
    copy_to_uspace(data, &call.data, sizeof(call.data));
217
 
230
 
218
    return 0;
231
    return 0;
219
}
232
}
220
 
233
 
221
/** Synchronous IPC call allowing to send whole message */
234
/** Synchronous IPC call allowing to send whole message */
222
__native sys_ipc_call_sync(__native phoneid, __native *question,
235
__native sys_ipc_call_sync(__native phoneid, __native *question,
223
               __native *reply)
236
               __native *reply)
224
{
237
{
225
    call_t call;
238
    call_t call;
226
    phone_t *phone;
239
    phone_t *phone;
227
 
240
 
228
    phone = get_phone(phoneid);
241
    phone = get_phone(phoneid);
229
    if (!phone)
242
    if (!phone)
230
        return ENOENT;
243
        return ENOENT;
231
 
244
 
232
    ipc_call_init(&call);
245
    ipc_call_init(&call);
233
    copy_from_uspace(&call.data, question, sizeof(call.data));
246
    copy_from_uspace(&call.data, question, sizeof(call.data));
234
 
247
 
235
    if (is_system_method(IPC_GET_METHOD(call.data)))
248
    if (is_system_method(IPC_GET_METHOD(call.data)))
236
        return EPERM;
249
        return EPERM;
237
   
250
   
238
    ipc_call_sync(phone, &call);
251
    ipc_call_sync(phone, &call);
239
 
252
 
240
    copy_to_uspace(reply, &call.data, sizeof(call.data));
253
    copy_to_uspace(reply, &call.data, sizeof(call.data));
241
 
254
 
242
    return 0;
255
    return 0;
243
}
256
}
244
 
257
 
245
/** Check that the task did not exceed allowed limit
258
/** Check that the task did not exceed allowed limit
246
 *
259
 *
247
 * @return 0 - Limit OK,   -1 - limit exceeded
260
 * @return 0 - Limit OK,   -1 - limit exceeded
248
 */
261
 */
249
static int check_call_limit(void)
262
static int check_call_limit(void)
250
{
263
{
251
    if (atomic_preinc(&TASK->active_calls) > IPC_MAX_ASYNC_CALLS) {
264
    if (atomic_preinc(&TASK->active_calls) > IPC_MAX_ASYNC_CALLS) {
252
        atomic_dec(&TASK->active_calls);
265
        atomic_dec(&TASK->active_calls);
253
        return -1;
266
        return -1;
254
    }
267
    }
255
    return 0;
268
    return 0;
256
}
269
}
257
 
270
 
258
/** Send an asynchronous call over ipc
271
/** Send an asynchronous call over ipc
259
 *
272
 *
260
 * @return Call identification, returns -1 on fatal error,
273
 * @return Call identification, returns -1 on fatal error,
261
           -2 on 'Too many async request, handle answers first
274
           -2 on 'Too many async request, handle answers first
262
 */
275
 */
263
__native sys_ipc_call_async_fast(__native phoneid, __native method,
276
__native sys_ipc_call_async_fast(__native phoneid, __native method,
264
                 __native arg1, __native arg2)
277
                 __native arg1, __native arg2)
265
{
278
{
266
    call_t *call;
279
    call_t *call;
267
    phone_t *phone;
280
    phone_t *phone;
268
 
281
 
269
    phone = get_phone(phoneid);
282
    phone = get_phone(phoneid);
270
    if (!phone)
283
    if (!phone)
271
        return IPC_CALLRET_FATAL;
284
        return IPC_CALLRET_FATAL;
272
 
285
 
273
    if (is_system_method(method))
286
    if (is_system_method(method))
274
        return IPC_CALLRET_FATAL;
287
        return IPC_CALLRET_FATAL;
275
 
288
 
276
    if (check_call_limit())
289
    if (check_call_limit())
277
        return IPC_CALLRET_TEMPORARY;
290
        return IPC_CALLRET_TEMPORARY;
278
 
291
 
279
    call = ipc_call_alloc();
292
    call = ipc_call_alloc();
280
    IPC_SET_METHOD(call->data, method);
293
    IPC_SET_METHOD(call->data, method);
281
    IPC_SET_ARG1(call->data, arg1);
294
    IPC_SET_ARG1(call->data, arg1);
282
    IPC_SET_ARG2(call->data, arg2);
295
    IPC_SET_ARG2(call->data, arg2);
283
 
296
 
284
    ipc_call(phone, call);
297
    ipc_call(phone, call);
285
 
298
 
286
    return (__native) call;
299
    return (__native) call;
287
}
300
}
288
 
301
 
289
/** Synchronous IPC call allowing to send whole message
302
/** Synchronous IPC call allowing to send whole message
290
 *
303
 *
291
 * @return The same as sys_ipc_call_async
304
 * @return The same as sys_ipc_call_async
292
 */
305
 */
293
__native sys_ipc_call_async(__native phoneid, __native *data)
306
__native sys_ipc_call_async(__native phoneid, __native *data)
294
{
307
{
295
    call_t *call;
308
    call_t *call;
296
    phone_t *phone;
309
    phone_t *phone;
297
 
310
 
298
    phone = get_phone(phoneid);
311
    phone = get_phone(phoneid);
299
    if (!phone)
312
    if (!phone)
300
        return IPC_CALLRET_FATAL;
313
        return IPC_CALLRET_FATAL;
301
 
314
 
302
    if (check_call_limit())
315
    if (check_call_limit())
303
        return IPC_CALLRET_TEMPORARY;
316
        return IPC_CALLRET_TEMPORARY;
304
 
317
 
305
    call = ipc_call_alloc();
318
    call = ipc_call_alloc();
306
    copy_from_uspace(&call->data, data, sizeof(call->data));
319
    copy_from_uspace(&call->data, data, sizeof(call->data));
307
 
320
 
308
    if (is_system_method(IPC_GET_METHOD(call->data))) {
321
    if (is_system_method(IPC_GET_METHOD(call->data))) {
309
        ipc_call_free(call);
322
        ipc_call_free(call);
310
        return EPERM;
323
        return EPERM;
311
    }
324
    }
312
   
325
   
313
    ipc_call(phone, call);
326
    ipc_call(phone, call);
314
 
327
 
315
    return (__native) call;
328
    return (__native) call;
316
}
329
}
317
 
330
 
318
/** Forward received call to another destination
331
/** Forward received call to another destination
319
 *
332
 *
320
 * The arg1 and arg2 are changed in the forwarded message
333
 * The arg1 and arg2 are changed in the forwarded message
-
 
334
 *
-
 
335
 * Warning: If implementing non-fast version, make sure that
-
 
336
 *          arg3 is not rewritten for certain system IPC
321
 */
337
 */
322
__native sys_ipc_forward_fast(__native callid, __native phoneid,
338
__native sys_ipc_forward_fast(__native callid, __native phoneid,
323
                  __native method, __native arg1)
339
                  __native method, __native arg1)
324
{
340
{
325
    call_t *call;
341
    call_t *call;
326
    phone_t *phone;
342
    phone_t *phone;
327
 
343
 
328
    call = get_call(callid);
344
    call = get_call(callid);
329
    if (!call)
345
    if (!call)
330
        return ENOENT;
346
        return ENOENT;
331
 
347
 
332
    phone = get_phone(phoneid);
348
    phone = get_phone(phoneid);
333
    if (!phone) {
349
    if (!phone) {
334
        IPC_SET_RETVAL(call->data, EFORWARD);
350
        IPC_SET_RETVAL(call->data, EFORWARD);
335
        ipc_answer(&TASK->answerbox, call);
351
        ipc_answer(&TASK->answerbox, call);
336
        return ENOENT;
352
        return ENOENT;
337
    }
353
    }
338
 
354
 
339
    if (!is_forwardable(IPC_GET_METHOD(call->data))) {
355
    if (!is_forwardable(IPC_GET_METHOD(call->data))) {
340
        IPC_SET_RETVAL(call->data, EFORWARD);
356
        IPC_SET_RETVAL(call->data, EFORWARD);
341
        ipc_answer(&TASK->answerbox, call);
357
        ipc_answer(&TASK->answerbox, call);
342
        return EPERM;
358
        return EPERM;
343
    }
359
    }
344
 
360
 
345
    /* Userspace is not allowed to change method of system methods
361
    /* Userspace is not allowed to change method of system methods
346
     * on forward, allow changing ARG1 and ARG2 by means of method and arg1
362
     * on forward, allow changing ARG1 and ARG2 by means of method and arg1
347
     */
363
     */
348
    if (is_system_method(IPC_GET_METHOD(call->data))) {
364
    if (is_system_method(IPC_GET_METHOD(call->data))) {
349
        IPC_SET_ARG1(call->data, method);
365
        IPC_SET_ARG1(call->data, method);
350
        IPC_SET_ARG2(call->data, arg1);
366
        IPC_SET_ARG2(call->data, arg1);
351
    } else {
367
    } else {
352
        IPC_SET_METHOD(call->data, method);
368
        IPC_SET_METHOD(call->data, method);
353
        IPC_SET_ARG1(call->data, arg1);
369
        IPC_SET_ARG1(call->data, arg1);
354
    }
370
    }
355
 
371
 
356
    ipc_forward(call, phone->callee, &TASK->answerbox);
372
    ipc_forward(call, phone->callee, &TASK->answerbox);
357
 
373
 
358
    return 0;
374
    return 0;
359
}
375
}
360
 
376
 
361
/** Send IPC answer */
377
/** Send IPC answer */
362
__native sys_ipc_answer_fast(__native callid, __native retval,
378
__native sys_ipc_answer_fast(__native callid, __native retval,
363
                 __native arg1, __native arg2)
379
                 __native arg1, __native arg2)
364
{
380
{
365
    call_t *call;
381
    call_t *call;
366
    ipc_data_t saved_data;
382
    ipc_data_t saved_data;
367
    int preprocess = 0;
383
    int preprocess = 0;
368
 
384
 
369
    call = get_call(callid);
385
    call = get_call(callid);
370
    if (!call)
386
    if (!call)
371
        return ENOENT;
387
        return ENOENT;
372
 
388
 
373
    if (answer_will_preprocess(call)) {
389
    if (answer_will_preprocess(call)) {
374
        memcpy(&saved_data, &call->data, sizeof(call->data));
390
        memcpy(&saved_data, &call->data, sizeof(call->data));
375
        preprocess = 1;
391
        preprocess = 1;
376
    }
392
    }
377
 
393
 
378
    IPC_SET_RETVAL(call->data, retval);
394
    IPC_SET_RETVAL(call->data, retval);
379
    IPC_SET_ARG1(call->data, arg1);
395
    IPC_SET_ARG1(call->data, arg1);
380
    IPC_SET_ARG2(call->data, arg2);
396
    IPC_SET_ARG2(call->data, arg2);
381
 
397
 
382
    if (preprocess)
398
    if (preprocess)
383
        answer_preprocess(call, &saved_data);
399
        answer_preprocess(call, &saved_data);
384
 
400
 
385
    ipc_answer(&TASK->answerbox, call);
401
    ipc_answer(&TASK->answerbox, call);
386
    return 0;
402
    return 0;
387
}
403
}
388
 
404
 
389
/** Send IPC answer */
405
/** Send IPC answer */
390
inline __native sys_ipc_answer(__native callid, __native *data)
406
inline __native sys_ipc_answer(__native callid, __native *data)
391
{
407
{
392
    call_t *call;
408
    call_t *call;
393
    ipc_data_t saved_data;
409
    ipc_data_t saved_data;
394
    int preprocess = 0;
410
    int preprocess = 0;
395
 
411
 
396
    call = get_call(callid);
412
    call = get_call(callid);
397
    if (!call)
413
    if (!call)
398
        return ENOENT;
414
        return ENOENT;
399
 
415
 
400
    if (answer_will_preprocess(call)) {
416
    if (answer_will_preprocess(call)) {
401
        memcpy(&saved_data, &call->data, sizeof(call->data));
417
        memcpy(&saved_data, &call->data, sizeof(call->data));
402
        preprocess = 1;
418
        preprocess = 1;
403
    }
419
    }
404
    copy_from_uspace(&call->data, data, sizeof(call->data));
420
    copy_from_uspace(&call->data, data, sizeof(call->data));
405
 
421
 
406
    if (preprocess)
422
    if (preprocess)
407
        answer_preprocess(call, &saved_data);
423
        answer_preprocess(call, &saved_data);
408
   
424
   
409
    ipc_answer(&TASK->answerbox, call);
425
    ipc_answer(&TASK->answerbox, call);
410
 
426
 
411
    return 0;
427
    return 0;
412
}
428
}
413
 
429
 
414
/** Ask the other side of connection to do 'callback' connection
430
/** Ask the other side of connection to do 'callback' connection
415
 *
431
 *
416
 * @return 0 if no error, error otherwise
432
 * @return 0 if no error, error otherwise
417
 */
433
 */
418
__native sys_ipc_connect_to_me(__native phoneid, __native arg1,
434
__native sys_ipc_connect_to_me(__native phoneid, __native arg1,
419
                   __native arg2, task_id_t *taskid)
435
                   __native arg2, task_id_t *taskid)
420
{
436
{
421
    call_t call;
437
    call_t call;
422
    phone_t *phone;
438
    phone_t *phone;
423
 
439
 
424
    phone = get_phone(phoneid);
440
    phone = get_phone(phoneid);
425
    if (!phone)
441
    if (!phone)
426
        return ENOENT;
442
        return ENOENT;
427
 
443
 
428
    ipc_call_init(&call);
444
    ipc_call_init(&call);
429
    IPC_SET_METHOD(call.data, IPC_M_CONNECTTOME);
445
    IPC_SET_METHOD(call.data, IPC_M_CONNECTTOME);
430
    IPC_SET_ARG1(call.data, arg1);
446
    IPC_SET_ARG1(call.data, arg1);
431
    IPC_SET_ARG2(call.data, arg2);
447
    IPC_SET_ARG2(call.data, arg2);
432
   
448
   
433
    ipc_call_sync(phone, &call);
449
    ipc_call_sync(phone, &call);
434
 
450
 
435
    if (!IPC_GET_RETVAL(call.data) && taskid)
451
    if (!IPC_GET_RETVAL(call.data) && taskid)
436
        copy_to_uspace(taskid,
452
        copy_to_uspace(taskid,
437
                   &phone->callee->task->taskid,
453
                   &phone->callee->task->taskid,
438
                   sizeof(TASK->taskid));
454
                   sizeof(TASK->taskid));
-
 
455
 
439
    return IPC_GET_RETVAL(call.data);
456
    return IPC_GET_RETVAL(call.data);
440
}
457
}
441
 
458
 
442
/** Ask target process to connect me somewhere
459
/** Ask target process to connect me somewhere
443
 *
460
 *
444
 * @return phoneid - on success, error otherwise
461
 * @return phoneid - on success, error otherwise
445
 */
462
 */
446
__native sys_ipc_connect_me_to(__native phoneid, __native arg1,
463
__native sys_ipc_connect_me_to(__native phoneid, __native arg1,
447
                   __native arg2)
464
                   __native arg2)
448
{
465
{
449
    call_t call;
466
    call_t call;
450
    phone_t *phone;
467
    phone_t *phone;
-
 
468
    int newphid;
451
 
469
 
452
    phone = get_phone(phoneid);
470
    phone = get_phone(phoneid);
453
    if (!phone)
471
    if (!phone)
454
        return ENOENT;
472
        return ENOENT;
455
 
473
 
-
 
474
    newphid = phone_alloc();
-
 
475
    if (newphid < 0)
-
 
476
        return ELIMIT;
-
 
477
 
456
    ipc_call_init(&call);
478
    ipc_call_init(&call);
457
    IPC_SET_METHOD(call.data, IPC_M_CONNECTMETO);
479
    IPC_SET_METHOD(call.data, IPC_M_CONNECTMETO);
458
    IPC_SET_ARG1(call.data, arg1);
480
    IPC_SET_ARG1(call.data, arg1);
459
    IPC_SET_ARG2(call.data, arg2);
481
    IPC_SET_ARG2(call.data, arg2);
-
 
482
    IPC_SET_ARG3(call.data, (__native)&TASK->phones[newphid]);
460
 
483
 
461
    ipc_call_sync(phone, &call);
484
    ipc_call_sync(phone, &call);
-
 
485
 
462
    if (!IPC_GET_RETVAL(call.data)) {
486
    if (IPC_GET_RETVAL(call.data)) { /* Connection failed */
-
 
487
        phone_dealloc(newphid);
463
        /* Everybody accepted, we should be connected by now */
488
        return IPC_GET_RETVAL(call.data);
464
    }
489
    }
465
 
490
 
466
    return 0;
491
    return newphid;
467
}
492
}
468
 
493
 
469
/** Wait for incoming ipc call or answer
494
/** Wait for incoming ipc call or answer
470
 *
495
 *
471
 * Generic function - can serve either as inkernel or userspace call
496
 * Generic function - can serve either as inkernel or userspace call
472
 * - inside kernel does probably unnecessary copying of data (TODO)
497
 * - inside kernel does probably unnecessary copying of data (TODO)
473
 *
498
 *
474
 * @param result
499
 * @param result
475
 * @param taskid
500
 * @param taskid
476
 * @param flags
501
 * @param flags
477
 * @return Callid, if callid & 1, then the call is answer
502
 * @return Callid, if callid & 1, then the call is answer
478
 */
503
 */
479
inline __native sys_ipc_wait_for_call(ipc_data_t *calldata,
504
inline __native sys_ipc_wait_for_call(ipc_data_t *calldata,
480
                      task_id_t *taskid,
505
                      task_id_t *taskid,
481
                      __native flags)
506
                      __native flags)
482
                         
507
                         
483
{
508
{
484
    call_t *call;
509
    call_t *call;
485
 
510
 
486
restart:   
511
restart:   
487
    call = ipc_wait_for_call(&TASK->answerbox, flags);
512
    call = ipc_wait_for_call(&TASK->answerbox, flags);
488
    printf("Received call %P from sender: %P\n", call, call->sender);
-
 
489
 
513
 
490
    if (call->flags & IPC_CALL_ANSWERED) {
514
    if (call->flags & IPC_CALL_ANSWERED) {
491
        if (process_answer(&TASK->answerbox, call))
515
        if (process_answer(&TASK->answerbox, call))
492
            goto restart;
516
            goto restart;
493
 
517
 
494
        copy_to_uspace(calldata, &call->data, sizeof(call->data));
518
        copy_to_uspace(calldata, &call->data, sizeof(call->data));
495
        atomic_dec(&TASK->active_calls);
519
        atomic_dec(&TASK->active_calls);
496
        ASSERT(! (call->flags & IPC_CALL_STATIC_ALLOC));
520
        ASSERT(! (call->flags & IPC_CALL_STATIC_ALLOC));
497
        ipc_call_free(call);
521
        ipc_call_free(call);
498
 
522
 
499
        return ((__native)call) | IPC_CALLID_ANSWERED;
523
        return ((__native)call) | IPC_CALLID_ANSWERED;
500
    }
524
    }
501
    if (process_request(&TASK->answerbox, call))
525
    if (process_request(&TASK->answerbox, call))
502
        goto restart;
526
        goto restart;
503
    copy_to_uspace(calldata, &call->data, sizeof(call->data));
527
    copy_to_uspace(calldata, &call->data, sizeof(call->data));
504
    copy_to_uspace(taskid, (void *)&TASK->taskid, sizeof(TASK->taskid));
528
    copy_to_uspace(taskid, (void *)&TASK->taskid, sizeof(TASK->taskid));
505
    return (__native)call;
529
    return (__native)call;
506
}
530
}
507
 
531
 
508
 
532