Subversion Repositories HelenOS-historic

Rev

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

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