Subversion Repositories HelenOS

Rev

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

Rev 2098 Rev 2359
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
/** @addtogroup genericipc
29
/** @addtogroup genericipc
30
 * @{
30
 * @{
31
 */
31
 */
32
/** @file
32
/** @file
33
 */
33
 */
34
 
34
 
35
#include <arch.h>
35
#include <arch.h>
36
#include <proc/task.h>
36
#include <proc/task.h>
37
#include <proc/thread.h>
37
#include <proc/thread.h>
38
#include <errno.h>
38
#include <errno.h>
39
#include <memstr.h>
39
#include <memstr.h>
40
#include <debug.h>
40
#include <debug.h>
41
#include <ipc/ipc.h>
41
#include <ipc/ipc.h>
42
#include <ipc/sysipc.h>
42
#include <ipc/sysipc.h>
43
#include <ipc/irq.h>
43
#include <ipc/irq.h>
44
#include <ipc/ipcrsc.h>
44
#include <ipc/ipcrsc.h>
45
#include <arch/interrupt.h>
45
#include <arch/interrupt.h>
46
#include <print.h>
46
#include <print.h>
47
#include <syscall/copy.h>
47
#include <syscall/copy.h>
48
#include <security/cap.h>
48
#include <security/cap.h>
49
#include <mm/as.h>
49
#include <mm/as.h>
50
#include <print.h>
50
#include <print.h>
51
 
51
 
52
#define GET_CHECK_PHONE(phone,phoneid,err) { \
52
#define GET_CHECK_PHONE(phone, phoneid, err) { \
53
      if (phoneid > IPC_MAX_PHONES) { err; } \
53
      if (phoneid > IPC_MAX_PHONES) { err; } \
54
      phone = &TASK->phones[phoneid]; \
54
      phone = &TASK->phones[phoneid]; \
55
}
55
}
56
 
56
 
57
#define STRUCT_TO_USPACE(dst,src) copy_to_uspace(dst,src,sizeof(*(src)))
57
#define STRUCT_TO_USPACE(dst, src) copy_to_uspace(dst, src, sizeof(*(src)))
58
 
58
 
59
/** Return true if the method is a system method */
59
/** Return true if the method is a system method */
60
static inline int is_system_method(unative_t method)
60
static inline int is_system_method(unative_t method)
61
{
61
{
62
    if (method <= IPC_M_LAST_SYSTEM)
62
    if (method <= IPC_M_LAST_SYSTEM)
63
        return 1;
63
        return 1;
64
    return 0;
64
    return 0;
65
}
65
}
66
 
66
 
67
/** Return true if the message with this method is forwardable
67
/** Return true if the message with this method is forwardable
68
 *
68
 *
69
 * - some system messages may be forwarded, for some of them
69
 * - some system messages may be forwarded, for some of them
70
 *   it is useless
70
 *   it is useless
71
 */
71
 */
72
static inline int is_forwardable(unative_t method)
72
static inline int is_forwardable(unative_t method)
73
{
73
{
74
    if (method == IPC_M_PHONE_HUNGUP || method == IPC_M_AS_AREA_SEND \
74
    if (method == IPC_M_PHONE_HUNGUP || method == IPC_M_AS_AREA_SEND ||
75
        || method == IPC_M_AS_AREA_RECV)
75
        method == IPC_M_AS_AREA_RECV)
76
        return 0; /* This message is meant only for the receiver */
76
        return 0; /* This message is meant only for the receiver */
77
    return 1;
77
    return 1;
78
}
78
}
79
 
79
 
80
/****************************************************/
80
/****************************************************/
81
/* Functions that preprocess answer before sending
81
/* Functions that preprocess answer before sending
82
 * it to the recepient
82
 * it to the recepient
83
 */
83
 */
84
 
84
 
85
/** Return true if the caller (ipc_answer) should save
85
/** Return true if the caller (ipc_answer) should save
86
 * the old call contents for answer_preprocess
86
 * the old call contents for answer_preprocess
87
 */
87
 */
88
static inline int answer_need_old(call_t *call)
88
static inline int answer_need_old(call_t *call)
89
{
89
{
90
    if (IPC_GET_METHOD(call->data) == IPC_M_CONNECT_TO_ME)
90
    if (IPC_GET_METHOD(call->data) == IPC_M_CONNECT_TO_ME)
91
        return 1;
91
        return 1;
92
    if (IPC_GET_METHOD(call->data) == IPC_M_CONNECT_ME_TO)
92
    if (IPC_GET_METHOD(call->data) == IPC_M_CONNECT_ME_TO)
93
        return 1;
93
        return 1;
94
    if (IPC_GET_METHOD(call->data) == IPC_M_AS_AREA_SEND)
94
    if (IPC_GET_METHOD(call->data) == IPC_M_AS_AREA_SEND)
95
        return 1;
95
        return 1;
96
    if (IPC_GET_METHOD(call->data) == IPC_M_AS_AREA_RECV)
96
    if (IPC_GET_METHOD(call->data) == IPC_M_AS_AREA_RECV)
97
        return 1;
97
        return 1;
98
    return 0;
98
    return 0;
99
}
99
}
100
 
100
 
101
/** Interpret process answer as control information
101
/** Interpret process answer as control information
102
 *
102
 *
103
 * This function is called directly after sys_ipc_answer
103
 * This function is called directly after sys_ipc_answer
104
 */
104
 */
105
static inline int answer_preprocess(call_t *answer, ipc_data_t *olddata)
105
static inline int answer_preprocess(call_t *answer, ipc_data_t *olddata)
106
{
106
{
107
    int phoneid;
107
    int phoneid;
108
 
108
 
109
    if (IPC_GET_RETVAL(answer->data) == EHANGUP) {
109
    if (IPC_GET_RETVAL(answer->data) == EHANGUP) {
110
        /* In case of forward, hangup the forwared phone,
110
        /* In case of forward, hangup the forwared phone,
111
         * not the originator
111
         * not the originator
112
         */
112
         */
113
        spinlock_lock(&answer->data.phone->lock);
113
        spinlock_lock(&answer->data.phone->lock);
114
        spinlock_lock(&TASK->answerbox.lock);
114
        spinlock_lock(&TASK->answerbox.lock);
115
        if (answer->data.phone->state == IPC_PHONE_CONNECTED) {
115
        if (answer->data.phone->state == IPC_PHONE_CONNECTED) {
116
            list_remove(&answer->data.phone->link);
116
            list_remove(&answer->data.phone->link);
117
            answer->data.phone->state = IPC_PHONE_SLAMMED;
117
            answer->data.phone->state = IPC_PHONE_SLAMMED;
118
        }
118
        }
119
        spinlock_unlock(&TASK->answerbox.lock);
119
        spinlock_unlock(&TASK->answerbox.lock);
120
        spinlock_unlock(&answer->data.phone->lock);
120
        spinlock_unlock(&answer->data.phone->lock);
121
    }
121
    }
122
 
122
 
123
    if (!olddata)
123
    if (!olddata)
124
        return 0;
124
        return 0;
125
 
125
 
126
    if (IPC_GET_METHOD(*olddata) == IPC_M_CONNECT_TO_ME) {
126
    if (IPC_GET_METHOD(*olddata) == IPC_M_CONNECT_TO_ME) {
127
        phoneid = IPC_GET_ARG3(*olddata);
127
        phoneid = IPC_GET_ARG3(*olddata);
128
        if (IPC_GET_RETVAL(answer->data)) {
128
        if (IPC_GET_RETVAL(answer->data)) {
129
            /* The connection was not accepted */
129
            /* The connection was not accepted */
130
            phone_dealloc(phoneid);
130
            phone_dealloc(phoneid);
131
        } else {
131
        } else {
132
            /* The connection was accepted */
132
            /* The connection was accepted */
133
            phone_connect(phoneid,&answer->sender->answerbox);
133
            phone_connect(phoneid, &answer->sender->answerbox);
134
            /* Set 'phone identification' as arg3 of response */
134
            /* Set 'phone identification' as arg3 of response */
-
 
135
            IPC_SET_ARG3(answer->data,
135
            IPC_SET_ARG3(answer->data, (unative_t)&TASK->phones[phoneid]);
136
                (unative_t) &TASK->phones[phoneid]);
136
        }
137
        }
137
    } else if (IPC_GET_METHOD(*olddata) == IPC_M_CONNECT_ME_TO) {
138
    } else if (IPC_GET_METHOD(*olddata) == IPC_M_CONNECT_ME_TO) {
138
        /* If the users accepted call, connect */
139
        /* If the users accepted call, connect */
139
        if (!IPC_GET_RETVAL(answer->data)) {
140
        if (!IPC_GET_RETVAL(answer->data)) {
140
            ipc_phone_connect((phone_t *)IPC_GET_ARG3(*olddata),
141
            ipc_phone_connect((phone_t *) IPC_GET_ARG3(*olddata),
141
                      &TASK->answerbox);
142
                &TASK->answerbox);
142
        }
143
        }
143
    } else if (IPC_GET_METHOD(*olddata) == IPC_M_AS_AREA_SEND) {
144
    } else if (IPC_GET_METHOD(*olddata) == IPC_M_AS_AREA_SEND) {
-
 
145
        if (!IPC_GET_RETVAL(answer->data)) {
144
        if (!IPC_GET_RETVAL(answer->data)) { /* Accepted, handle as_area receipt */
146
            /* Accepted, handle as_area receipt */
145
            ipl_t ipl;
147
            ipl_t ipl;
146
            int rc;
148
            int rc;
147
            as_t *as;
149
            as_t *as;
148
           
150
           
149
            ipl = interrupts_disable();
151
            ipl = interrupts_disable();
150
            spinlock_lock(&answer->sender->lock);
152
            spinlock_lock(&answer->sender->lock);
151
            as = answer->sender->as;
153
            as = answer->sender->as;
152
            spinlock_unlock(&answer->sender->lock);
154
            spinlock_unlock(&answer->sender->lock);
153
            interrupts_restore(ipl);
155
            interrupts_restore(ipl);
154
           
156
           
155
            rc = as_area_share(as, IPC_GET_ARG1(*olddata), IPC_GET_ARG2(*olddata),
157
            rc = as_area_share(as, IPC_GET_ARG1(*olddata),
-
 
158
                IPC_GET_ARG2(*olddata), AS,
156
                       AS, IPC_GET_ARG1(answer->data), IPC_GET_ARG3(*olddata));
159
                IPC_GET_ARG1(answer->data), IPC_GET_ARG3(*olddata));
157
            IPC_SET_RETVAL(answer->data, rc);
160
            IPC_SET_RETVAL(answer->data, rc);
158
            return rc;
161
            return rc;
159
        }
162
        }
160
    } else if (IPC_GET_METHOD(*olddata) == IPC_M_AS_AREA_RECV) {
163
    } else if (IPC_GET_METHOD(*olddata) == IPC_M_AS_AREA_RECV) {
161
        if (!IPC_GET_RETVAL(answer->data)) {
164
        if (!IPC_GET_RETVAL(answer->data)) {
162
            ipl_t ipl;
165
            ipl_t ipl;
163
            as_t *as;
166
            as_t *as;
164
            int rc;
167
            int rc;
165
           
168
           
166
            ipl = interrupts_disable();
169
            ipl = interrupts_disable();
167
            spinlock_lock(&answer->sender->lock);
170
            spinlock_lock(&answer->sender->lock);
168
            as = answer->sender->as;
171
            as = answer->sender->as;
169
            spinlock_unlock(&answer->sender->lock);
172
            spinlock_unlock(&answer->sender->lock);
170
            interrupts_restore(ipl);
173
            interrupts_restore(ipl);
171
           
174
           
172
            rc = as_area_share(AS, IPC_GET_ARG1(answer->data), IPC_GET_ARG2(*olddata),
175
            rc = as_area_share(AS, IPC_GET_ARG1(answer->data),
173
                       as, IPC_GET_ARG1(*olddata), IPC_GET_ARG2(answer->data));
176
                IPC_GET_ARG2(*olddata), as, IPC_GET_ARG1(*olddata),
-
 
177
                IPC_GET_ARG2(answer->data));
174
            IPC_SET_RETVAL(answer->data, rc);
178
            IPC_SET_RETVAL(answer->data, rc);
175
        }
179
        }
176
    }
180
    }
177
    return 0;
181
    return 0;
178
}
182
}
179
 
183
 
180
/** Called before the request is sent
184
/** Called before the request is sent
181
 *
185
 *
182
 * @return 0 - no error, -1 - report error to user
186
 * @return 0 - no error, -1 - report error to user
183
 */
187
 */
184
static int request_preprocess(call_t *call)
188
static int request_preprocess(call_t *call)
185
{
189
{
186
    int newphid;
190
    int newphid;
187
    size_t size;
191
    size_t size;
188
 
192
 
189
    switch (IPC_GET_METHOD(call->data)) {
193
    switch (IPC_GET_METHOD(call->data)) {
190
    case IPC_M_CONNECT_ME_TO:
194
    case IPC_M_CONNECT_ME_TO:
191
        newphid = phone_alloc();
195
        newphid = phone_alloc();
192
        if (newphid < 0)
196
        if (newphid < 0)
193
            return ELIMIT;
197
            return ELIMIT;
194
        /* Set arg3 for server */
198
        /* Set arg3 for server */
195
        IPC_SET_ARG3(call->data, (unative_t)&TASK->phones[newphid]);
199
        IPC_SET_ARG3(call->data, (unative_t) &TASK->phones[newphid]);
196
        call->flags |= IPC_CALL_CONN_ME_TO;
200
        call->flags |= IPC_CALL_CONN_ME_TO;
197
        call->priv = newphid;
201
        call->priv = newphid;
198
        break;
202
        break;
199
    case IPC_M_AS_AREA_SEND:
203
    case IPC_M_AS_AREA_SEND:
200
        size = as_get_size(IPC_GET_ARG1(call->data));
204
        size = as_get_size(IPC_GET_ARG1(call->data));
201
        if (!size) {
205
        if (!size) {
202
            return EPERM;
206
            return EPERM;
203
        }
207
        }
204
        IPC_SET_ARG2(call->data, size);
208
        IPC_SET_ARG2(call->data, size);
205
        break;
209
        break;
206
    default:
210
    default:
207
        break;
211
        break;
208
    }
212
    }
209
    return 0;
213
    return 0;
210
}
214
}
211
 
215
 
212
/****************************************************/
216
/****************************************************/
213
/* Functions called to process received call/answer
217
/* Functions called to process received call/answer
214
 * before passing to uspace
218
 * before passing to uspace
215
 */
219
 */
216
 
220
 
217
/** Do basic kernel processing of received call answer */
221
/** Do basic kernel processing of received call answer */
218
static void process_answer(call_t *call)
222
static void process_answer(call_t *call)
219
{
223
{
220
    if (IPC_GET_RETVAL(call->data) == EHANGUP && \
224
    if (IPC_GET_RETVAL(call->data) == EHANGUP &&
221
        call->flags & IPC_CALL_FORWARDED)
225
        (call->flags & IPC_CALL_FORWARDED))
222
        IPC_SET_RETVAL(call->data, EFORWARD);
226
        IPC_SET_RETVAL(call->data, EFORWARD);
223
 
227
 
224
    if (call->flags & IPC_CALL_CONN_ME_TO) {
228
    if (call->flags & IPC_CALL_CONN_ME_TO) {
225
        if (IPC_GET_RETVAL(call->data))
229
        if (IPC_GET_RETVAL(call->data))
226
            phone_dealloc(call->priv);
230
            phone_dealloc(call->priv);
227
        else
231
        else
228
            IPC_SET_ARG3(call->data, call->priv);
232
            IPC_SET_ARG3(call->data, call->priv);
229
    }
233
    }
230
}
234
}
231
 
235
 
232
/** Do basic kernel processing of received call request
236
/** Do basic kernel processing of received call request
233
 *
237
 *
234
 * @return 0 - the call should be passed to userspace, 1 - ignore call
238
 * @return 0 - the call should be passed to userspace, 1 - ignore call
235
 */
239
 */
236
static int process_request(answerbox_t *box,call_t *call)
240
static int process_request(answerbox_t *box, call_t *call)
237
{
241
{
238
    int phoneid;
242
    int phoneid;
239
 
243
 
240
    if (IPC_GET_METHOD(call->data) == IPC_M_CONNECT_TO_ME) {
244
    if (IPC_GET_METHOD(call->data) == IPC_M_CONNECT_TO_ME) {
241
        phoneid = phone_alloc();
245
        phoneid = phone_alloc();
242
        if (phoneid < 0) { /* Failed to allocate phone */
246
        if (phoneid < 0) { /* Failed to allocate phone */
243
            IPC_SET_RETVAL(call->data, ELIMIT);
247
            IPC_SET_RETVAL(call->data, ELIMIT);
244
            ipc_answer(box,call);
248
            ipc_answer(box,call);
245
            return -1;
249
            return -1;
246
        }
250
        }
247
        IPC_SET_ARG3(call->data, phoneid);
251
        IPC_SET_ARG3(call->data, phoneid);
248
    }
252
    }
249
    return 0;
253
    return 0;
250
}
254
}
251
 
255
 
252
/** Send a call over IPC, wait for reply, return to user
256
/** Send a call over IPC, wait for reply, return to user
253
 *
257
 *
254
 * @return Call identification, returns -1 on fatal error,
258
 * @return Call identification, returns -1 on fatal error,
255
           -2 on 'Too many async request, handle answers first
259
           -2 on 'Too many async request, handle answers first
256
 */
260
 */
257
unative_t sys_ipc_call_sync_fast(unative_t phoneid, unative_t method,
261
unative_t sys_ipc_call_sync_fast(unative_t phoneid, unative_t method,
258
                unative_t arg1, ipc_data_t *data)
262
    unative_t arg1, ipc_data_t *data)
259
{
263
{
260
    call_t call;
264
    call_t call;
261
    phone_t *phone;
265
    phone_t *phone;
262
    int res;
266
    int res;
263
 
267
 
264
    GET_CHECK_PHONE(phone, phoneid, return ENOENT);
268
    GET_CHECK_PHONE(phone, phoneid, return ENOENT);
265
 
269
 
266
    ipc_call_static_init(&call);
270
    ipc_call_static_init(&call);
267
    IPC_SET_METHOD(call.data, method);
271
    IPC_SET_METHOD(call.data, method);
268
    IPC_SET_ARG1(call.data, arg1);
272
    IPC_SET_ARG1(call.data, arg1);
269
 
273
 
270
    if (!(res=request_preprocess(&call))) {
274
    if (!(res=request_preprocess(&call))) {
271
        ipc_call_sync(phone, &call);
275
        ipc_call_sync(phone, &call);
272
        process_answer(&call);
276
        process_answer(&call);
273
    } else
277
    } else
274
        IPC_SET_RETVAL(call.data, res);
278
        IPC_SET_RETVAL(call.data, res);
275
    STRUCT_TO_USPACE(&data->args, &call.data.args);
279
    STRUCT_TO_USPACE(&data->args, &call.data.args);
276
 
280
 
277
    return 0;
281
    return 0;
278
}
282
}
279
 
283
 
280
/** Synchronous IPC call allowing to send whole message */
284
/** Synchronous IPC call allowing to send whole message */
281
unative_t sys_ipc_call_sync(unative_t phoneid, ipc_data_t *question,
285
unative_t sys_ipc_call_sync(unative_t phoneid, ipc_data_t *question,
282
               ipc_data_t *reply)
286
    ipc_data_t *reply)
283
{
287
{
284
    call_t call;
288
    call_t call;
285
    phone_t *phone;
289
    phone_t *phone;
286
    int res;
290
    int res;
287
    int rc;
291
    int rc;
288
 
292
 
289
    ipc_call_static_init(&call);
293
    ipc_call_static_init(&call);
290
    rc = copy_from_uspace(&call.data.args, &question->args, sizeof(call.data.args));
294
    rc = copy_from_uspace(&call.data.args, &question->args,
-
 
295
        sizeof(call.data.args));
291
    if (rc != 0)
296
    if (rc != 0)
292
        return (unative_t) rc;
297
        return (unative_t) rc;
293
 
298
 
294
    GET_CHECK_PHONE(phone, phoneid, return ENOENT);
299
    GET_CHECK_PHONE(phone, phoneid, return ENOENT);
295
 
300
 
296
    if (!(res=request_preprocess(&call))) {
301
    if (!(res=request_preprocess(&call))) {
297
        ipc_call_sync(phone, &call);
302
        ipc_call_sync(phone, &call);
298
        process_answer(&call);
303
        process_answer(&call);
299
    } else
304
    } else
300
        IPC_SET_RETVAL(call.data, res);
305
        IPC_SET_RETVAL(call.data, res);
301
 
306
 
302
    rc = STRUCT_TO_USPACE(&reply->args, &call.data.args);
307
    rc = STRUCT_TO_USPACE(&reply->args, &call.data.args);
303
    if (rc != 0)
308
    if (rc != 0)
304
        return rc;
309
        return rc;
305
 
310
 
306
    return 0;
311
    return 0;
307
}
312
}
308
 
313
 
309
/** Check that the task did not exceed allowed limit
314
/** Check that the task did not exceed allowed limit
310
 *
315
 *
311
 * @return 0 - Limit OK,   -1 - limit exceeded
316
 * @return 0 - Limit OK,   -1 - limit exceeded
312
 */
317
 */
313
static int check_call_limit(void)
318
static int check_call_limit(void)
314
{
319
{
315
    if (atomic_preinc(&TASK->active_calls) > IPC_MAX_ASYNC_CALLS) {
320
    if (atomic_preinc(&TASK->active_calls) > IPC_MAX_ASYNC_CALLS) {
316
        atomic_dec(&TASK->active_calls);
321
        atomic_dec(&TASK->active_calls);
317
        return -1;
322
        return -1;
318
    }
323
    }
319
    return 0;
324
    return 0;
320
}
325
}
321
 
326
 
322
/** Send an asynchronous call over ipc
327
/** Send an asynchronous call over ipc
323
 *
328
 *
324
 * @return Call identification, returns -1 on fatal error,
329
 * @return Call identification, returns -1 on fatal error,
325
           -2 on 'Too many async request, handle answers first
330
           -2 on 'Too many async request, handle answers first
326
 */
331
 */
327
unative_t sys_ipc_call_async_fast(unative_t phoneid, unative_t method,
332
unative_t sys_ipc_call_async_fast(unative_t phoneid, unative_t method,
328
                 unative_t arg1, unative_t arg2)
333
    unative_t arg1, unative_t arg2)
329
{
334
{
330
    call_t *call;
335
    call_t *call;
331
    phone_t *phone;
336
    phone_t *phone;
332
    int res;
337
    int res;
333
 
338
 
334
    if (check_call_limit())
339
    if (check_call_limit())
335
        return IPC_CALLRET_TEMPORARY;
340
        return IPC_CALLRET_TEMPORARY;
336
 
341
 
337
    GET_CHECK_PHONE(phone, phoneid, return IPC_CALLRET_FATAL);
342
    GET_CHECK_PHONE(phone, phoneid, return IPC_CALLRET_FATAL);
338
 
343
 
339
    call = ipc_call_alloc(0);
344
    call = ipc_call_alloc(0);
340
    IPC_SET_METHOD(call->data, method);
345
    IPC_SET_METHOD(call->data, method);
341
    IPC_SET_ARG1(call->data, arg1);
346
    IPC_SET_ARG1(call->data, arg1);
342
    IPC_SET_ARG2(call->data, arg2);
347
    IPC_SET_ARG2(call->data, arg2);
343
    IPC_SET_ARG3(call->data, 0);
348
    IPC_SET_ARG3(call->data, 0);
344
 
349
 
345
    if (!(res=request_preprocess(call)))
350
    if (!(res = request_preprocess(call)))
346
        ipc_call(phone, call);
351
        ipc_call(phone, call);
347
    else
352
    else
348
        ipc_backsend_err(phone, call, res);
353
        ipc_backsend_err(phone, call, res);
349
 
354
 
350
    return (unative_t) call;
355
    return (unative_t) call;
351
}
356
}
352
 
357
 
353
/** Synchronous IPC call allowing to send whole message
358
/** Synchronous IPC call allowing to send whole message
354
 *
359
 *
355
 * @return The same as sys_ipc_call_async
360
 * @return The same as sys_ipc_call_async
356
 */
361
 */
357
unative_t sys_ipc_call_async(unative_t phoneid, ipc_data_t *data)
362
unative_t sys_ipc_call_async(unative_t phoneid, ipc_data_t *data)
358
{
363
{
359
    call_t *call;
364
    call_t *call;
360
    phone_t *phone;
365
    phone_t *phone;
361
    int res;
366
    int res;
362
    int rc;
367
    int rc;
363
 
368
 
364
    if (check_call_limit())
369
    if (check_call_limit())
365
        return IPC_CALLRET_TEMPORARY;
370
        return IPC_CALLRET_TEMPORARY;
366
 
371
 
367
    GET_CHECK_PHONE(phone, phoneid, return IPC_CALLRET_FATAL);
372
    GET_CHECK_PHONE(phone, phoneid, return IPC_CALLRET_FATAL);
368
 
373
 
369
    call = ipc_call_alloc(0);
374
    call = ipc_call_alloc(0);
370
    rc = copy_from_uspace(&call->data.args, &data->args, sizeof(call->data.args));
375
    rc = copy_from_uspace(&call->data.args, &data->args,
-
 
376
        sizeof(call->data.args));
371
    if (rc != 0) {
377
    if (rc != 0) {
372
        ipc_call_free(call);
378
        ipc_call_free(call);
373
        return (unative_t) rc;
379
        return (unative_t) rc;
374
    }
380
    }
375
    if (!(res=request_preprocess(call)))
381
    if (!(res = request_preprocess(call)))
376
        ipc_call(phone, call);
382
        ipc_call(phone, call);
377
    else
383
    else
378
        ipc_backsend_err(phone, call, res);
384
        ipc_backsend_err(phone, call, res);
379
 
385
 
380
    return (unative_t) call;
386
    return (unative_t) call;
381
}
387
}
382
 
388
 
383
/** Forward received call to another destination
389
/** Forward received call to another destination
384
 *
390
 *
385
 * The arg1 and arg2 are changed in the forwarded message
391
 * The arg1 and arg2 are changed in the forwarded message
386
 *
392
 *
387
 * Warning: If implementing non-fast version, make sure that
393
 * Warning: If implementing non-fast version, make sure that
388
 *          arg3 is not rewritten for certain system IPC
394
 *          arg3 is not rewritten for certain system IPC
389
 */
395
 */
390
unative_t sys_ipc_forward_fast(unative_t callid, unative_t phoneid,
396
unative_t sys_ipc_forward_fast(unative_t callid, unative_t phoneid,
391
                  unative_t method, unative_t arg1)
397
    unative_t method, unative_t arg1)
392
{
398
{
393
    call_t *call;
399
    call_t *call;
394
    phone_t *phone;
400
    phone_t *phone;
395
 
401
 
396
    call = get_call(callid);
402
    call = get_call(callid);
397
    if (!call)
403
    if (!call)
398
        return ENOENT;
404
        return ENOENT;
399
 
405
 
400
    call->flags |= IPC_CALL_FORWARDED;
406
    call->flags |= IPC_CALL_FORWARDED;
401
 
407
 
402
    GET_CHECK_PHONE(phone, phoneid, {
408
    GET_CHECK_PHONE(phone, phoneid, {
403
        IPC_SET_RETVAL(call->data, EFORWARD);
409
        IPC_SET_RETVAL(call->data, EFORWARD);
404
        ipc_answer(&TASK->answerbox, call);
410
        ipc_answer(&TASK->answerbox, call);
405
        return ENOENT;
411
        return ENOENT;
406
    });    
412
    });    
407
 
413
 
408
    if (!is_forwardable(IPC_GET_METHOD(call->data))) {
414
    if (!is_forwardable(IPC_GET_METHOD(call->data))) {
409
        IPC_SET_RETVAL(call->data, EFORWARD);
415
        IPC_SET_RETVAL(call->data, EFORWARD);
410
        ipc_answer(&TASK->answerbox, call);
416
        ipc_answer(&TASK->answerbox, call);
411
        return EPERM;
417
        return EPERM;
412
    }
418
    }
413
 
419
 
414
    /* Userspace is not allowed to change method of system methods
420
    /* Userspace is not allowed to change method of system methods
415
     * on forward, allow changing ARG1 and ARG2 by means of method and arg1
421
     * on forward, allow changing ARG1 and ARG2 by means of method and arg1
416
     */
422
     */
417
    if (is_system_method(IPC_GET_METHOD(call->data))) {
423
    if (is_system_method(IPC_GET_METHOD(call->data))) {
418
        if (IPC_GET_METHOD(call->data) == IPC_M_CONNECT_TO_ME)
424
        if (IPC_GET_METHOD(call->data) == IPC_M_CONNECT_TO_ME)
419
            phone_dealloc(IPC_GET_ARG3(call->data));
425
            phone_dealloc(IPC_GET_ARG3(call->data));
420
 
426
 
421
        IPC_SET_ARG1(call->data, method);
427
        IPC_SET_ARG1(call->data, method);
422
        IPC_SET_ARG2(call->data, arg1);
428
        IPC_SET_ARG2(call->data, arg1);
423
    } else {
429
    } else {
424
        IPC_SET_METHOD(call->data, method);
430
        IPC_SET_METHOD(call->data, method);
425
        IPC_SET_ARG1(call->data, arg1);
431
        IPC_SET_ARG1(call->data, arg1);
426
    }
432
    }
427
 
433
 
428
    return ipc_forward(call, phone, &TASK->answerbox);
434
    return ipc_forward(call, phone, &TASK->answerbox);
429
}
435
}
430
 
436
 
431
/** Send IPC answer */
437
/** Send IPC answer */
432
unative_t sys_ipc_answer_fast(unative_t callid, unative_t retval,
438
unative_t sys_ipc_answer_fast(unative_t callid, unative_t retval,
433
                 unative_t arg1, unative_t arg2)
439
    unative_t arg1, unative_t arg2)
434
{
440
{
435
    call_t *call;
441
    call_t *call;
436
    ipc_data_t saved_data;
442
    ipc_data_t saved_data;
437
    int saveddata = 0;
443
    int saveddata = 0;
438
    int rc;
444
    int rc;
439
 
445
 
440
    /* Do not answer notification callids */
446
    /* Do not answer notification callids */
441
    if (callid & IPC_CALLID_NOTIFICATION)
447
    if (callid & IPC_CALLID_NOTIFICATION)
442
        return 0;
448
        return 0;
443
 
449
 
444
    call = get_call(callid);
450
    call = get_call(callid);
445
    if (!call)
451
    if (!call)
446
        return ENOENT;
452
        return ENOENT;
447
 
453
 
448
    if (answer_need_old(call)) {
454
    if (answer_need_old(call)) {
449
        memcpy(&saved_data, &call->data, sizeof(call->data));
455
        memcpy(&saved_data, &call->data, sizeof(call->data));
450
        saveddata = 1;
456
        saveddata = 1;
451
    }
457
    }
452
 
458
 
453
    IPC_SET_RETVAL(call->data, retval);
459
    IPC_SET_RETVAL(call->data, retval);
454
    IPC_SET_ARG1(call->data, arg1);
460
    IPC_SET_ARG1(call->data, arg1);
455
    IPC_SET_ARG2(call->data, arg2);
461
    IPC_SET_ARG2(call->data, arg2);
456
    rc = answer_preprocess(call, saveddata ? &saved_data : NULL);
462
    rc = answer_preprocess(call, saveddata ? &saved_data : NULL);
457
 
463
 
458
    ipc_answer(&TASK->answerbox, call);
464
    ipc_answer(&TASK->answerbox, call);
459
    return rc;
465
    return rc;
460
}
466
}
461
 
467
 
462
/** Send IPC answer */
468
/** Send IPC answer */
463
unative_t sys_ipc_answer(unative_t callid, ipc_data_t *data)
469
unative_t sys_ipc_answer(unative_t callid, ipc_data_t *data)
464
{
470
{
465
    call_t *call;
471
    call_t *call;
466
    ipc_data_t saved_data;
472
    ipc_data_t saved_data;
467
    int saveddata = 0;
473
    int saveddata = 0;
468
    int rc;
474
    int rc;
469
 
475
 
470
    /* Do not answer notification callids */
476
    /* Do not answer notification callids */
471
    if (callid & IPC_CALLID_NOTIFICATION)
477
    if (callid & IPC_CALLID_NOTIFICATION)
472
        return 0;
478
        return 0;
473
 
479
 
474
    call = get_call(callid);
480
    call = get_call(callid);
475
    if (!call)
481
    if (!call)
476
        return ENOENT;
482
        return ENOENT;
477
 
483
 
478
    if (answer_need_old(call)) {
484
    if (answer_need_old(call)) {
479
        memcpy(&saved_data, &call->data, sizeof(call->data));
485
        memcpy(&saved_data, &call->data, sizeof(call->data));
480
        saveddata = 1;
486
        saveddata = 1;
481
    }
487
    }
482
    rc = copy_from_uspace(&call->data.args, &data->args,
488
    rc = copy_from_uspace(&call->data.args, &data->args,
483
             sizeof(call->data.args));
489
        sizeof(call->data.args));
484
    if (rc != 0)
490
    if (rc != 0)
485
        return rc;
491
        return rc;
486
 
492
 
487
    rc = answer_preprocess(call, saveddata ? &saved_data : NULL);
493
    rc = answer_preprocess(call, saveddata ? &saved_data : NULL);
488
   
494
   
489
    ipc_answer(&TASK->answerbox, call);
495
    ipc_answer(&TASK->answerbox, call);
490
 
496
 
491
    return rc;
497
    return rc;
492
}
498
}
493
 
499
 
494
/** Hang up the phone
500
/** Hang up the phone
495
 *
501
 *
496
 */
502
 */
497
unative_t sys_ipc_hangup(int phoneid)
503
unative_t sys_ipc_hangup(int phoneid)
498
{
504
{
499
    phone_t *phone;
505
    phone_t *phone;
500
 
506
 
501
    GET_CHECK_PHONE(phone, phoneid, return ENOENT);
507
    GET_CHECK_PHONE(phone, phoneid, return ENOENT);
502
 
508
 
503
    if (ipc_phone_hangup(phone))
509
    if (ipc_phone_hangup(phone))
504
        return -1;
510
        return -1;
505
 
511
 
506
    return 0;
512
    return 0;
507
}
513
}
508
 
514
 
509
/** Wait for incoming ipc call or answer
515
/** Wait for incoming ipc call or answer
510
 *
516
 *
511
 * @param calldata Pointer to buffer where the call/answer data is stored
517
 * @param calldata  Pointer to buffer where the call/answer data is stored.
512
 * @param usec Timeout. See waitq_sleep_timeout() for explanation.
518
 * @param usec      Timeout. See waitq_sleep_timeout() for explanation.
513
 * @param flags Select mode of sleep operation. See waitq_sleep_timeout() for explanation.
519
 * @param flags     Select mode of sleep operation. See waitq_sleep_timeout()
-
 
520
 *          for explanation.
514
 *
521
 *
515
 * @return Callid, if callid & 1, then the call is answer
522
 * @return Callid, if callid & 1, then the call is answer
516
 */
523
 */
517
unative_t sys_ipc_wait_for_call(ipc_data_t *calldata, uint32_t usec, int flags)
524
unative_t sys_ipc_wait_for_call(ipc_data_t *calldata, uint32_t usec, int flags)
518
{
525
{
519
    call_t *call;
526
    call_t *call;
520
 
527
 
521
restart:   
528
restart:   
522
    call = ipc_wait_for_call(&TASK->answerbox, usec, flags | SYNCH_FLAGS_INTERRUPTIBLE);
529
    call = ipc_wait_for_call(&TASK->answerbox, usec,
-
 
530
        flags | SYNCH_FLAGS_INTERRUPTIBLE);
523
    if (!call)
531
    if (!call)
524
        return 0;
532
        return 0;
525
 
533
 
526
    if (call->flags & IPC_CALL_NOTIF) {
534
    if (call->flags & IPC_CALL_NOTIF) {
527
        ASSERT(! (call->flags & IPC_CALL_STATIC_ALLOC));
535
        ASSERT(! (call->flags & IPC_CALL_STATIC_ALLOC));
528
 
536
 
529
        /* Set in_phone_hash to the interrupt counter */
537
        /* Set in_phone_hash to the interrupt counter */
530
        call->data.phone = (void *) call->priv;
538
        call->data.phone = (void *) call->priv;
531
       
539
       
532
        STRUCT_TO_USPACE(calldata, &call->data);
540
        STRUCT_TO_USPACE(calldata, &call->data);
533
 
541
 
534
        ipc_call_free(call);
542
        ipc_call_free(call);
535
       
543
       
536
        return ((unative_t)call) | IPC_CALLID_NOTIFICATION;
544
        return ((unative_t)call) | IPC_CALLID_NOTIFICATION;
537
    }
545
    }
538
 
546
 
539
    if (call->flags & IPC_CALL_ANSWERED) {
547
    if (call->flags & IPC_CALL_ANSWERED) {
540
        process_answer(call);
548
        process_answer(call);
541
 
549
 
542
        ASSERT(! (call->flags & IPC_CALL_STATIC_ALLOC));
550
        ASSERT(! (call->flags & IPC_CALL_STATIC_ALLOC));
543
 
551
 
544
        atomic_dec(&TASK->active_calls);
552
        atomic_dec(&TASK->active_calls);
545
 
553
 
546
        if (call->flags & IPC_CALL_DISCARD_ANSWER) {
554
        if (call->flags & IPC_CALL_DISCARD_ANSWER) {
547
            ipc_call_free(call);
555
            ipc_call_free(call);
548
            goto restart;
556
            goto restart;
549
        }
557
        }
550
 
558
 
551
        STRUCT_TO_USPACE(&calldata->args, &call->data.args);
559
        STRUCT_TO_USPACE(&calldata->args, &call->data.args);
552
        ipc_call_free(call);
560
        ipc_call_free(call);
553
 
561
 
554
        return ((unative_t)call) | IPC_CALLID_ANSWERED;
562
        return ((unative_t)call) | IPC_CALLID_ANSWERED;
555
    }
563
    }
556
 
564
 
557
    if (process_request(&TASK->answerbox, call))
565
    if (process_request(&TASK->answerbox, call))
558
        goto restart;
566
        goto restart;
559
 
567
 
560
    /* Include phone address('id') of the caller in the request,
568
    /* Include phone address('id') of the caller in the request,
561
     * copy whole call->data, not only call->data.args */
569
     * copy whole call->data, not only call->data.args */
562
    if (STRUCT_TO_USPACE(calldata, &call->data)) {
570
    if (STRUCT_TO_USPACE(calldata, &call->data)) {
563
        return 0;
571
        return 0;
564
    }
572
    }
565
    return (unative_t)call;
573
    return (unative_t)call;
566
}
574
}
567
 
575
 
568
/** Connect irq handler to task.
576
/** Connect irq handler to task.
569
 *
577
 *
570
 * @param inr IRQ number.
578
 * @param inr IRQ number.
571
 * @param devno Device number.
579
 * @param devno Device number.
572
 * @param method Method to be associated with the notification.
580
 * @param method Method to be associated with the notification.
573
 * @param ucode Uspace pointer to the top-half pseudocode.
581
 * @param ucode Uspace pointer to the top-half pseudocode.
574
 *
582
 *
575
 * @return EPERM or a return code returned by ipc_irq_register().
583
 * @return EPERM or a return code returned by ipc_irq_register().
576
 */
584
 */
577
unative_t sys_ipc_register_irq(inr_t inr, devno_t devno, unative_t method, irq_code_t *ucode)
585
unative_t sys_ipc_register_irq(inr_t inr, devno_t devno, unative_t method,
-
 
586
    irq_code_t *ucode)
578
{
587
{
579
    if (!(cap_get(TASK) & CAP_IRQ_REG))
588
    if (!(cap_get(TASK) & CAP_IRQ_REG))
580
        return EPERM;
589
        return EPERM;
581
 
590
 
582
    return ipc_irq_register(&TASK->answerbox, inr, devno, method, ucode);
591
    return ipc_irq_register(&TASK->answerbox, inr, devno, method, ucode);
583
}
592
}
584
 
593
 
585
/** Disconnect irq handler from task.
594
/** Disconnect irq handler from task.
586
 *
595
 *
587
 * @param inr IRQ number.
596
 * @param inr IRQ number.
588
 * @param devno Device number.
597
 * @param devno Device number.
589
 */
598
 */
590
unative_t sys_ipc_unregister_irq(inr_t inr, devno_t devno)
599
unative_t sys_ipc_unregister_irq(inr_t inr, devno_t devno)
591
{
600
{
592
    if (!(cap_get(TASK) & CAP_IRQ_REG))
601
    if (!(cap_get(TASK) & CAP_IRQ_REG))
593
        return EPERM;
602
        return EPERM;
594
 
603
 
595
    ipc_irq_unregister(&TASK->answerbox, inr, devno);
604
    ipc_irq_unregister(&TASK->answerbox, inr, devno);
596
 
605
 
597
    return 0;
606
    return 0;
598
}
607
}
599
 
608
 
600
/** @}
609
/** @}
601
 */
610
 */
602
 
611