Subversion Repositories HelenOS

Rev

Rev 2098 | Rev 2471 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 2098 Rev 2359
Line 47... Line 47...
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)
Line 69... Line 69...
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
/****************************************************/
Line 128... Line 128...
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)) {
Line 167... Line 170...
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
}
Line 190... Line 194...
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));
Line 215... Line 219...
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);
Line 231... Line 235...
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();
Line 252... Line 256...
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
 
Line 276... Line 280...
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
 
Line 322... Line 327...
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
 
Line 340... Line 345...
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;
Line 365... Line 370...
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;
Line 386... Line 392...
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);
Line 427... Line 433...
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;
Line 478... Line 484...
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
   
Line 506... Line 512...
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));
Line 572... Line 580...
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);