Changes in kernel/generic/src/ipc/sysipc.c [fa3b8e4:c9fff17] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
kernel/generic/src/ipc/sysipc.c
rfa3b8e4 rc9fff17 56 56 * requests. 57 57 */ 58 #define DATA_XFER_LIMIT (64 * 1024) 59 60 #define STRUCT_TO_USPACE(dst, src) copy_to_uspace((dst), (src), sizeof(*(src))) 58 #define DATA_XFER_LIMIT (64 * 1024) 61 59 62 60 /** Get phone from the current task by ID. 63 61 * 64 * @param phoneid Phone ID. 65 * @param phone Place to store pointer to phone. 66 * 67 * @return EOK on success, EINVAL if ID is invalid. 68 * 62 * @param phoneid Phone ID. 63 * @param phone Place to store pointer to phone. 64 * @return EOK on success, EINVAL if ID is invalid. 69 65 */ 70 66 static int phone_get(unative_t phoneid, phone_t **phone) … … 72 68 if (phoneid >= IPC_MAX_PHONES) 73 69 return EINVAL; 74 70 75 71 *phone = &TASK->phones[phoneid]; 76 72 return EOK; 77 73 } 78 74 75 #define STRUCT_TO_USPACE(dst, src) copy_to_uspace(dst, src, sizeof(*(src))) 76 79 77 /** Decide if the method is a system method. 80 78 * 81 * @param method 82 * 83 * @return trueif the method is a system method.84 * 85 */ 86 static inline boolmethod_is_system(unative_t method)79 * @param method Method to be decided. 80 * 81 * @return Return 1 if the method is a system method. 82 * Otherwise return 0. 83 */ 84 static inline int method_is_system(unative_t method) 87 85 { 88 86 if (method <= IPC_M_LAST_SYSTEM) 89 return true; 90 91 return false; 87 return 1; 88 return 0; 92 89 } 93 90 … … 97 94 * it is useless 98 95 * 99 * @param method 100 * 101 * @return trueif the method is forwardable.102 * 103 */ 104 static inline boolmethod_is_forwardable(unative_t method)96 * @param method Method to be decided. 97 * 98 * @return Return 1 if the method is forwardable. 99 * Otherwise return 0. 100 */ 101 static inline int method_is_forwardable(unative_t method) 105 102 { 106 103 switch (method) { … … 109 106 case IPC_M_PHONE_HUNGUP: 110 107 /* This message is meant only for the original recipient. */ 111 return false;108 return 0; 112 109 default: 113 return true;110 return 1; 114 111 } 115 112 } … … 119 116 * - some system messages may be forwarded but their content cannot be altered 120 117 * 121 * @param method 122 * 123 * @return trueif the method is immutable on forward.124 * 125 */ 126 static inline boolmethod_is_immutable(unative_t method)118 * @param method Method to be decided. 119 * 120 * @return Return 1 if the method is immutable on forward. 121 * Otherwise return 0. 122 */ 123 static inline int method_is_immutable(unative_t method) 127 124 { 128 125 switch (method) { … … 131 128 case IPC_M_DATA_WRITE: 132 129 case IPC_M_DATA_READ: 133 return true;130 return 1; 134 131 default: 135 return false;132 return 0; 136 133 } 137 134 } … … 145 142 * for answer_preprocess(). 146 143 * 147 * @param call 148 * 149 * @return trueif the old call contents should be saved.150 * 151 */ 152 static inline boolanswer_need_old(call_t *call)144 * @param call Call structure to be decided. 145 * 146 * @return Return 1 if the old call contents should be saved. 147 * Return 0 otherwise. 148 */ 149 static inline int answer_need_old(call_t *call) 153 150 { 154 151 switch (IPC_GET_METHOD(call->data)) { … … 161 158 case IPC_M_DATA_WRITE: 162 159 case IPC_M_DATA_READ: 163 return true;160 return 1; 164 161 default: 165 return false;162 return 0; 166 163 } 167 164 } … … 171 168 * This function is called directly after sys_ipc_answer(). 172 169 * 173 * @param answer Call structure with the answer. 174 * @param olddata Saved data of the request. 175 * 176 * @return Return 0 on success or an error code. 177 * 170 * @param answer Call structure with the answer. 171 * @param olddata Saved data of the request. 172 * 173 * @return Return 0 on success or an error code. 178 174 */ 179 175 static inline int answer_preprocess(call_t *answer, ipc_data_t *olddata) 180 176 { 177 int phoneid; 178 181 179 if ((native_t) IPC_GET_RETVAL(answer->data) == EHANGUP) { 182 180 /* In case of forward, hangup the forwared phone, … … 184 182 */ 185 183 mutex_lock(&answer->data.phone->lock); 186 irq_spinlock_lock(&TASK->answerbox.lock, true);184 spinlock_lock(&TASK->answerbox.lock); 187 185 if (answer->data.phone->state == IPC_PHONE_CONNECTED) { 188 186 list_remove(&answer->data.phone->link); 189 187 answer->data.phone->state = IPC_PHONE_SLAMMED; 190 188 } 191 irq_spinlock_unlock(&TASK->answerbox.lock, true);189 spinlock_unlock(&TASK->answerbox.lock); 192 190 mutex_unlock(&answer->data.phone->lock); 193 191 } 194 192 195 193 if (!olddata) 196 194 return 0; 197 195 198 196 if (IPC_GET_METHOD(*olddata) == IPC_M_CONNECTION_CLONE) { 199 int phoneid = IPC_GET_ARG1(*olddata); 200 phone_t *phone = &TASK->phones[phoneid]; 201 197 phoneid = IPC_GET_ARG1(*olddata); 198 phone_t *phone = &TASK->phones[phoneid]; 202 199 if (IPC_GET_RETVAL(answer->data) != EOK) { 203 200 /* … … 211 208 mutex_lock(&phone->lock); 212 209 if (phone->state == IPC_PHONE_CONNECTED) { 213 irq_spinlock_lock(&phone->callee->lock, true);210 spinlock_lock(&phone->callee->lock); 214 211 list_remove(&phone->link); 215 212 phone->state = IPC_PHONE_SLAMMED; 216 irq_spinlock_unlock(&phone->callee->lock, true);213 spinlock_unlock(&phone->callee->lock); 217 214 } 218 215 mutex_unlock(&phone->lock); 219 216 } 220 217 } else if (IPC_GET_METHOD(*olddata) == IPC_M_CONNECT_ME) { 221 phone_t *phone = (phone_t *) IPC_GET_ARG5(*olddata); 222 218 phone_t *phone = (phone_t *)IPC_GET_ARG5(*olddata); 223 219 if (IPC_GET_RETVAL(answer->data) != EOK) { 224 220 /* … … 230 226 mutex_lock(&phone->lock); 231 227 if (phone->state == IPC_PHONE_CONNECTED) { 232 irq_spinlock_lock(&phone->callee->lock, true);228 spinlock_lock(&phone->callee->lock); 233 229 list_remove(&phone->link); 234 230 phone->state = IPC_PHONE_SLAMMED; 235 irq_spinlock_unlock(&phone->callee->lock, true);231 spinlock_unlock(&phone->callee->lock); 236 232 } 237 233 mutex_unlock(&phone->lock); 238 234 } 239 235 } else if (IPC_GET_METHOD(*olddata) == IPC_M_CONNECT_TO_ME) { 240 int phoneid = IPC_GET_ARG5(*olddata); 241 236 phoneid = IPC_GET_ARG5(*olddata); 242 237 if (IPC_GET_RETVAL(answer->data) != EOK) { 243 238 /* The connection was not accepted */ … … 259 254 if (!IPC_GET_RETVAL(answer->data)) { 260 255 /* Accepted, handle as_area receipt */ 256 ipl_t ipl; 257 int rc; 258 as_t *as; 261 259 262 irq_spinlock_lock(&answer->sender->lock, true); 263 as_t *as = answer->sender->as; 264 irq_spinlock_unlock(&answer->sender->lock, true); 260 ipl = interrupts_disable(); 261 spinlock_lock(&answer->sender->lock); 262 as = answer->sender->as; 263 spinlock_unlock(&answer->sender->lock); 264 interrupts_restore(ipl); 265 265 266 intrc = as_area_share(as, IPC_GET_ARG1(*olddata),266 rc = as_area_share(as, IPC_GET_ARG1(*olddata), 267 267 IPC_GET_ARG2(*olddata), AS, 268 268 IPC_GET_ARG1(answer->data), IPC_GET_ARG3(*olddata)); … … 272 272 } else if (IPC_GET_METHOD(*olddata) == IPC_M_SHARE_IN) { 273 273 if (!IPC_GET_RETVAL(answer->data)) { 274 i rq_spinlock_lock(&answer->sender->lock, true);275 as_t *as = answer->sender->as;276 i rq_spinlock_unlock(&answer->sender->lock, true);274 ipl_t ipl; 275 as_t *as; 276 int rc; 277 277 278 int rc = as_area_share(AS, IPC_GET_ARG1(answer->data), 278 ipl = interrupts_disable(); 279 spinlock_lock(&answer->sender->lock); 280 as = answer->sender->as; 281 spinlock_unlock(&answer->sender->lock); 282 interrupts_restore(ipl); 283 284 rc = as_area_share(AS, IPC_GET_ARG1(answer->data), 279 285 IPC_GET_ARG2(*olddata), as, IPC_GET_ARG1(*olddata), 280 286 IPC_GET_ARG2(answer->data)); … … 295 301 */ 296 302 IPC_SET_ARG1(answer->data, dst); 297 303 298 304 answer->buffer = malloc(size, 0); 299 305 int rc = copy_from_uspace(answer->buffer, … … 314 320 if (!IPC_GET_RETVAL(answer->data)) { 315 321 /* The recipient agreed to receive data. */ 316 uintptr_t dst = (uintptr_t)IPC_GET_ARG1(answer->data); 317 size_t size = (size_t)IPC_GET_ARG2(answer->data); 318 size_t max_size = (size_t)IPC_GET_ARG2(*olddata); 319 322 int rc; 323 uintptr_t dst; 324 size_t size; 325 size_t max_size; 326 327 dst = (uintptr_t)IPC_GET_ARG1(answer->data); 328 size = (size_t)IPC_GET_ARG2(answer->data); 329 max_size = (size_t)IPC_GET_ARG2(*olddata); 330 320 331 if (size <= max_size) { 321 intrc = copy_to_uspace((void *) dst,332 rc = copy_to_uspace((void *) dst, 322 333 answer->buffer, size); 323 334 if (rc) … … 330 341 answer->buffer = NULL; 331 342 } 332 333 343 return 0; 334 344 } … … 342 352 mutex_lock(&p2->lock); 343 353 mutex_lock(&p1->lock); 344 } else 354 } else { 345 355 mutex_lock(&p1->lock); 356 } 346 357 } 347 358 … … 355 366 /** Called before the request is sent. 356 367 * 357 * @param call Call structure with the request. 358 * @param phone Phone that the call will be sent through. 359 * 360 * @return Return 0 on success, ELIMIT or EPERM on error. 361 * 368 * @param call Call structure with the request. 369 * @param phone Phone that the call will be sent through. 370 * 371 * @return Return 0 on success, ELIMIT or EPERM on error. 362 372 */ 363 373 static int request_preprocess(call_t *call, phone_t *phone) 364 374 { 375 int newphid; 376 size_t size; 377 uintptr_t src; 378 int rc; 379 365 380 switch (IPC_GET_METHOD(call->data)) { 366 381 case IPC_M_CONNECTION_CLONE: { 367 382 phone_t *cloned_phone; 383 368 384 if (phone_get(IPC_GET_ARG1(call->data), &cloned_phone) != EOK) 369 385 return ENOENT; 370 371 386 phones_lock(cloned_phone, phone); 372 387 373 388 if ((cloned_phone->state != IPC_PHONE_CONNECTED) || 374 389 phone->state != IPC_PHONE_CONNECTED) { … … 376 391 return EINVAL; 377 392 } 378 379 393 /* 380 394 * We can be pretty sure now that both tasks exist and we are … … 382 396 * we are effectively preventing them from finishing their 383 397 * potential cleanup. 384 *385 398 */ 386 intnewphid = phone_alloc(phone->callee->task);399 newphid = phone_alloc(phone->callee->task); 387 400 if (newphid < 0) { 388 401 phones_unlock(cloned_phone, phone); 389 402 return ELIMIT; 390 403 } 391 392 404 ipc_phone_connect(&phone->callee->task->phones[newphid], 393 405 cloned_phone->callee); 394 406 phones_unlock(cloned_phone, phone); 395 396 407 /* Set the new phone for the callee. */ 397 408 IPC_SET_ARG1(call->data, newphid); … … 401 412 IPC_SET_ARG5(call->data, (unative_t) phone); 402 413 break; 403 case IPC_M_CONNECT_ME_TO: {404 intnewphid = phone_alloc(TASK);414 case IPC_M_CONNECT_ME_TO: 415 newphid = phone_alloc(TASK); 405 416 if (newphid < 0) 406 417 return ELIMIT; 407 408 418 /* Set arg5 for server */ 409 419 IPC_SET_ARG5(call->data, (unative_t) &TASK->phones[newphid]); … … 411 421 call->priv = newphid; 412 422 break; 413 } 414 case IPC_M_SHARE_OUT: { 415 size_t size = as_area_get_size(IPC_GET_ARG1(call->data)); 423 case IPC_M_SHARE_OUT: 424 size = as_area_get_size(IPC_GET_ARG1(call->data)); 416 425 if (!size) 417 426 return EPERM; 418 419 427 IPC_SET_ARG2(call->data, size); 420 428 break; 421 } 422 case IPC_M_DATA_READ: { 423 size_t size = IPC_GET_ARG2(call->data); 429 case IPC_M_DATA_READ: 430 size = IPC_GET_ARG2(call->data); 424 431 if ((size <= 0 || (size > DATA_XFER_LIMIT))) 425 432 return ELIMIT; 426 427 433 break; 428 } 429 case IPC_M_DATA_WRITE: { 430 uintptr_t src = IPC_GET_ARG1(call->data); 431 size_t size = IPC_GET_ARG2(call->data); 434 case IPC_M_DATA_WRITE: 435 src = IPC_GET_ARG1(call->data); 436 size = IPC_GET_ARG2(call->data); 432 437 433 438 if (size > DATA_XFER_LIMIT) … … 435 440 436 441 call->buffer = (uint8_t *) malloc(size, 0); 437 intrc = copy_from_uspace(call->buffer, (void *) src, size);442 rc = copy_from_uspace(call->buffer, (void *) src, size); 438 443 if (rc != 0) { 439 444 free(call->buffer); 440 445 return rc; 441 446 } 442 443 447 break; 444 }445 448 #ifdef CONFIG_UDEBUG 446 449 case IPC_M_DEBUG_ALL: … … 450 453 break; 451 454 } 452 453 455 return 0; 454 456 } … … 460 462 /** Do basic kernel processing of received call answer. 461 463 * 462 * @param call Call structure with the answer. 463 * 464 * @param call Call structure with the answer. 464 465 */ 465 466 static void process_answer(call_t *call) … … 468 469 (call->flags & IPC_CALL_FORWARDED)) 469 470 IPC_SET_RETVAL(call->data, EFORWARD); 470 471 471 472 if (call->flags & IPC_CALL_CONN_ME_TO) { 472 473 if (IPC_GET_RETVAL(call->data)) … … 475 476 IPC_SET_ARG5(call->data, call->priv); 476 477 } 477 478 478 479 if (call->buffer) { 479 /* 480 * This must be an affirmative answer to IPC_M_DATA_READ 481 * or IPC_M_DEBUG_ALL/UDEBUG_M_MEM_READ... 482 * 483 */ 480 /* This must be an affirmative answer to IPC_M_DATA_READ. */ 481 /* or IPC_M_DEBUG_ALL/UDEBUG_M_MEM_READ... */ 484 482 uintptr_t dst = IPC_GET_ARG1(call->data); 485 483 size_t size = IPC_GET_ARG2(call->data); … … 494 492 /** Do basic kernel processing of received call request. 495 493 * 496 * @param box Destination answerbox structure. 497 * @param call Call structure with the request. 498 * 499 * @return 0 if the call should be passed to userspace. 500 * @return -1 if the call should be ignored. 501 * 494 * @param box Destination answerbox structure. 495 * @param call Call structure with the request. 496 * 497 * @return Return 0 if the call should be passed to userspace. 498 * Return -1 if the call should be ignored. 502 499 */ 503 500 static int process_request(answerbox_t *box, call_t *call) 504 501 { 502 int phoneid; 503 505 504 if (IPC_GET_METHOD(call->data) == IPC_M_CONNECT_TO_ME) { 506 intphoneid = phone_alloc(TASK);505 phoneid = phone_alloc(TASK); 507 506 if (phoneid < 0) { /* Failed to allocate phone */ 508 507 IPC_SET_RETVAL(call->data, ELIMIT); … … 510 509 return -1; 511 510 } 512 513 511 IPC_SET_ARG5(call->data, phoneid); 514 512 } 515 516 513 switch (IPC_GET_METHOD(call->data)) { 517 514 case IPC_M_DEBUG_ALL: … … 520 517 break; 521 518 } 522 523 519 return 0; 524 520 } … … 529 525 * the generic function (i.e. sys_ipc_call_sync_slow()). 530 526 * 531 * @param phoneid Phone handle for the call. 532 * @param method Method of the call. 533 * @param arg1 Service-defined payload argument. 534 * @param arg2 Service-defined payload argument. 535 * @param arg3 Service-defined payload argument. 536 * @param data Address of userspace structure where the reply call will 537 * be stored. 538 * 539 * @return 0 on success. 540 * @return ENOENT if there is no such phone handle. 541 * 527 * @param phoneid Phone handle for the call. 528 * @param method Method of the call. 529 * @param arg1 Service-defined payload argument. 530 * @param arg2 Service-defined payload argument. 531 * @param arg3 Service-defined payload argument. 532 * @param data Address of userspace structure where the reply call will 533 * be stored. 534 * 535 * @return Returns 0 on success. 536 * Return ENOENT if there is no such phone handle. 542 537 */ 543 538 unative_t sys_ipc_call_sync_fast(unative_t phoneid, unative_t method, 544 539 unative_t arg1, unative_t arg2, unative_t arg3, ipc_data_t *data) 545 540 { 541 call_t *call; 546 542 phone_t *phone; 543 int res; 544 int rc; 545 547 546 if (phone_get(phoneid, &phone) != EOK) 548 547 return ENOENT; 549 548 550 call _t *call= ipc_call_alloc(0);549 call = ipc_call_alloc(0); 551 550 IPC_SET_METHOD(call->data, method); 552 551 IPC_SET_ARG1(call->data, arg1); 553 552 IPC_SET_ARG2(call->data, arg2); 554 553 IPC_SET_ARG3(call->data, arg3); 555 556 554 /* 557 555 * To achieve deterministic behavior, zero out arguments that are beyond … … 560 558 IPC_SET_ARG4(call->data, 0); 561 559 IPC_SET_ARG5(call->data, 0); 562 563 int res = request_preprocess(call, phone); 564 int rc; 565 566 if (!res) { 560 561 if (!(res = request_preprocess(call, phone))) { 567 562 #ifdef CONFIG_UDEBUG 568 563 udebug_stoppable_begin(); … … 572 567 udebug_stoppable_end(); 573 568 #endif 574 575 569 if (rc != EOK) { 576 570 /* The call will be freed by ipc_cleanup(). */ 577 571 return rc; 578 572 } 579 580 573 process_answer(call); 581 582 } else 574 575 } else { 583 576 IPC_SET_RETVAL(call->data, res); 584 577 } 585 578 rc = STRUCT_TO_USPACE(&data->args, &call->data.args); 586 579 ipc_call_free(call); 587 580 if (rc != 0) 588 581 return rc; 589 582 590 583 return 0; 591 584 } … … 593 586 /** Make a synchronous IPC call allowing to transmit the entire payload. 594 587 * 595 * @param phoneid Phone handle for the call. 596 * @param question Userspace address of call data with the request. 597 * @param reply Userspace address of call data where to store the 598 * answer. 599 * 600 * @return Zero on success or an error code. 601 * 588 * @param phoneid Phone handle for the call. 589 * @param question Userspace address of call data with the request. 590 * @param reply Userspace address of call data where to store the 591 * answer. 592 * 593 * @return Zero on success or an error code. 602 594 */ 603 595 unative_t sys_ipc_call_sync_slow(unative_t phoneid, ipc_data_t *question, 604 596 ipc_data_t *reply) 605 597 { 598 call_t *call; 606 599 phone_t *phone; 600 int res; 601 int rc; 602 607 603 if (phone_get(phoneid, &phone) != EOK) 608 604 return ENOENT; 609 605 610 call _t *call= ipc_call_alloc(0);611 intrc = copy_from_uspace(&call->data.args, &question->args,606 call = ipc_call_alloc(0); 607 rc = copy_from_uspace(&call->data.args, &question->args, 612 608 sizeof(call->data.args)); 613 609 if (rc != 0) { … … 615 611 return (unative_t) rc; 616 612 } 617 618 int res = request_preprocess(call, phone); 619 620 if (!res) { 613 614 615 if (!(res = request_preprocess(call, phone))) { 621 616 #ifdef CONFIG_UDEBUG 622 617 udebug_stoppable_begin(); … … 626 621 udebug_stoppable_end(); 627 622 #endif 628 629 623 if (rc != EOK) { 630 624 /* The call will be freed by ipc_cleanup(). */ 631 625 return rc; 632 626 } 633 634 627 process_answer(call); 635 } else 628 } else 636 629 IPC_SET_RETVAL(call->data, res); 637 630 638 631 rc = STRUCT_TO_USPACE(&reply->args, &call->data.args); 639 632 ipc_call_free(call); 640 633 if (rc != 0) 641 634 return rc; 642 635 643 636 return 0; 644 637 } … … 646 639 /** Check that the task did not exceed the allowed limit of asynchronous calls. 647 640 * 648 * @return 0 if limit not reached or -1 if limit exceeded. 649 * 641 * @return Return 0 if limit not reached or -1 if limit exceeded. 650 642 */ 651 643 static int check_call_limit(void) … … 655 647 return -1; 656 648 } 657 658 649 return 0; 659 650 } … … 664 655 * the generic function sys_ipc_call_async_slow(). 665 656 * 666 * @param phoneid Phone handle for the call. 667 * @param method Method of the call. 668 * @param arg1 Service-defined payload argument. 669 * @param arg2 Service-defined payload argument. 670 * @param arg3 Service-defined payload argument. 671 * @param arg4 Service-defined payload argument. 672 * 673 * @return Call hash on success. 674 * @return IPC_CALLRET_FATAL in case of a fatal error. 675 * @return IPC_CALLRET_TEMPORARY if there are too many pending 676 * asynchronous requests; answers should be handled first. 677 * 657 * @param phoneid Phone handle for the call. 658 * @param method Method of the call. 659 * @param arg1 Service-defined payload argument. 660 * @param arg2 Service-defined payload argument. 661 * @param arg3 Service-defined payload argument. 662 * @param arg4 Service-defined payload argument. 663 * 664 * @return Return call hash on success. 665 * Return IPC_CALLRET_FATAL in case of a fatal error and 666 * IPC_CALLRET_TEMPORARY if there are too many pending 667 * asynchronous requests; answers should be handled first. 678 668 */ 679 669 unative_t sys_ipc_call_async_fast(unative_t phoneid, unative_t method, 680 670 unative_t arg1, unative_t arg2, unative_t arg3, unative_t arg4) 681 671 { 672 call_t *call; 673 phone_t *phone; 674 int res; 675 682 676 if (check_call_limit()) 683 677 return IPC_CALLRET_TEMPORARY; 684 685 phone_t *phone; 678 686 679 if (phone_get(phoneid, &phone) != EOK) 687 680 return IPC_CALLRET_FATAL; 688 689 call _t *call= ipc_call_alloc(0);681 682 call = ipc_call_alloc(0); 690 683 IPC_SET_METHOD(call->data, method); 691 684 IPC_SET_ARG1(call->data, arg1); … … 693 686 IPC_SET_ARG3(call->data, arg3); 694 687 IPC_SET_ARG4(call->data, arg4); 695 696 688 /* 697 689 * To achieve deterministic behavior, zero out arguments that are beyond … … 699 691 */ 700 692 IPC_SET_ARG5(call->data, 0); 701 702 int res = request_preprocess(call, phone); 703 704 if (!res) 693 694 if (!(res = request_preprocess(call, phone))) 705 695 ipc_call(phone, call); 706 696 else 707 697 ipc_backsend_err(phone, call, res); 708 698 709 699 return (unative_t) call; 710 700 } … … 712 702 /** Make an asynchronous IPC call allowing to transmit the entire payload. 713 703 * 714 * @param phoneid Phone handle for the call. 715 * @param data Userspace address of call data with the request. 716 * 717 * @return See sys_ipc_call_async_fast(). 718 * 704 * @param phoneid Phone handle for the call. 705 * @param data Userspace address of call data with the request. 706 * 707 * @return See sys_ipc_call_async_fast(). 719 708 */ 720 709 unative_t sys_ipc_call_async_slow(unative_t phoneid, ipc_data_t *data) 721 710 { 711 call_t *call; 712 phone_t *phone; 713 int res; 714 int rc; 715 722 716 if (check_call_limit()) 723 717 return IPC_CALLRET_TEMPORARY; 724 725 phone_t *phone; 718 726 719 if (phone_get(phoneid, &phone) != EOK) 727 720 return IPC_CALLRET_FATAL; 728 721 729 call _t *call= ipc_call_alloc(0);730 intrc = copy_from_uspace(&call->data.args, &data->args,722 call = ipc_call_alloc(0); 723 rc = copy_from_uspace(&call->data.args, &data->args, 731 724 sizeof(call->data.args)); 732 725 if (rc != 0) { … … 734 727 return (unative_t) rc; 735 728 } 736 737 int res = request_preprocess(call, phone); 738 739 if (!res) 729 if (!(res = request_preprocess(call, phone))) 740 730 ipc_call(phone, call); 741 731 else 742 732 ipc_backsend_err(phone, call, res); 743 733 744 734 return (unative_t) call; 745 735 } 746 736 747 /** Forward a received call to another destination 748 * 749 * Common code for both the fast and the slow version. 750 * 751 * @param callid Hash of the call to forward. 752 * @param phoneid Phone handle to use for forwarding. 753 * @param method New method to use for the forwarded call. 754 * @param arg1 New value of the first argument for the forwarded call. 755 * @param arg2 New value of the second argument for the forwarded call. 756 * @param arg3 New value of the third argument for the forwarded call. 757 * @param arg4 New value of the fourth argument for the forwarded call. 758 * @param arg5 New value of the fifth argument for the forwarded call. 759 * @param mode Flags that specify mode of the forward operation. 760 * @param slow If true, arg3, arg4 and arg5 are considered. Otherwise 761 * the function considers only the fast version arguments: 762 * i.e. arg1 and arg2. 763 * 764 * @return 0 on succes, otherwise an error code. 765 * 766 * Warning: Make sure that ARG5 is not rewritten for certain system IPC 767 * 737 /** Forward a received call to another destination - common code for both the 738 * fast and the slow version. 739 * 740 * @param callid Hash of the call to forward. 741 * @param phoneid Phone handle to use for forwarding. 742 * @param method New method to use for the forwarded call. 743 * @param arg1 New value of the first argument for the forwarded call. 744 * @param arg2 New value of the second argument for the forwarded call. 745 * @param arg3 New value of the third argument for the forwarded call. 746 * @param arg4 New value of the fourth argument for the forwarded call. 747 * @param arg5 New value of the fifth argument for the forwarded call. 748 * @param mode Flags that specify mode of the forward operation. 749 * @param slow If true, arg3, arg4 and arg5 are considered. Otherwise 750 * the function considers only the fast version arguments: 751 * i.e. arg1 and arg2. 752 * 753 * @return Return 0 on succes, otherwise return an error code. 754 * 755 * Warning: Make sure that ARG5 is not rewritten for certain system IPC 768 756 */ 769 757 static unative_t sys_ipc_forward_common(unative_t callid, unative_t phoneid, 770 758 unative_t method, unative_t arg1, unative_t arg2, unative_t arg3, 771 unative_t arg4, unative_t arg5, unsigned int mode, bool slow) 772 { 773 call_t *call = get_call(callid); 759 unative_t arg4, unative_t arg5, int mode, bool slow) 760 { 761 call_t *call; 762 phone_t *phone; 763 764 call = get_call(callid); 774 765 if (!call) 775 766 return ENOENT; 776 767 777 768 call->flags |= IPC_CALL_FORWARDED; 778 779 phone_t *phone; 769 780 770 if (phone_get(phoneid, &phone) != EOK) { 781 771 IPC_SET_RETVAL(call->data, EFORWARD); … … 783 773 return ENOENT; 784 774 } 785 775 786 776 if (!method_is_forwardable(IPC_GET_METHOD(call->data))) { 787 777 IPC_SET_RETVAL(call->data, EFORWARD); … … 789 779 return EPERM; 790 780 } 791 781 792 782 /* 793 783 * Userspace is not allowed to change method of system methods on … … 800 790 if (IPC_GET_METHOD(call->data) == IPC_M_CONNECT_TO_ME) 801 791 phone_dealloc(IPC_GET_ARG5(call->data)); 802 792 803 793 IPC_SET_ARG1(call->data, method); 804 794 IPC_SET_ARG2(call->data, arg1); 805 795 IPC_SET_ARG3(call->data, arg2); 806 807 796 if (slow) { 808 797 IPC_SET_ARG4(call->data, arg3); … … 823 812 } 824 813 } 825 814 826 815 return ipc_forward(call, phone, &TASK->answerbox, mode); 827 816 } 828 817 829 818 /** Forward a received call to another destination - fast version. 819 * 820 * @param callid Hash of the call to forward. 821 * @param phoneid Phone handle to use for forwarding. 822 * @param method New method to use for the forwarded call. 823 * @param arg1 New value of the first argument for the forwarded call. 824 * @param arg2 New value of the second argument for the forwarded call. 825 * @param mode Flags that specify mode of the forward operation. 826 * 827 * @return Return 0 on succes, otherwise return an error code. 830 828 * 831 829 * In case the original method is a system method, ARG1, ARG2 and ARG3 are … … 835 833 * is a set of immutable methods, for which the new method and arguments are not 836 834 * set and these values are ignored. 837 *838 * @param callid Hash of the call to forward.839 * @param phoneid Phone handle to use for forwarding.840 * @param method New method to use for the forwarded call.841 * @param arg1 New value of the first argument for the forwarded call.842 * @param arg2 New value of the second argument for the forwarded call.843 * @param mode Flags that specify mode of the forward operation.844 *845 * @return 0 on succes, otherwise an error code.846 *847 835 */ 848 836 unative_t sys_ipc_forward_fast(unative_t callid, unative_t phoneid, 849 unative_t method, unative_t arg1, unative_t arg2, unsignedint mode)837 unative_t method, unative_t arg1, unative_t arg2, int mode) 850 838 { 851 839 return sys_ipc_forward_common(callid, phoneid, method, arg1, arg2, 0, 0, … … 854 842 855 843 /** Forward a received call to another destination - slow version. 844 * 845 * @param callid Hash of the call to forward. 846 * @param phoneid Phone handle to use for forwarding. 847 * @param data Userspace address of the new IPC data. 848 * @param mode Flags that specify mode of the forward operation. 849 * 850 * @return Return 0 on succes, otherwise return an error code. 856 851 * 857 852 * This function is the slow verision of the sys_ipc_forward_fast interface. … … 861 856 * methods, it additionally stores the new value of arg3, arg4 and arg5, 862 857 * respectively, to ARG3, ARG4 and ARG5, respectively. 863 *864 * @param callid Hash of the call to forward.865 * @param phoneid Phone handle to use for forwarding.866 * @param data Userspace address of the new IPC data.867 * @param mode Flags that specify mode of the forward operation.868 *869 * @return 0 on succes, otherwise an error code.870 *871 858 */ 872 859 unative_t sys_ipc_forward_slow(unative_t callid, unative_t phoneid, 873 ipc_data_t *data, unsignedint mode)860 ipc_data_t *data, int mode) 874 861 { 875 862 ipc_data_t newdata; 876 int rc = copy_from_uspace(&newdata.args, &data->args, 863 int rc; 864 865 rc = copy_from_uspace(&newdata.args, &data->args, 877 866 sizeof(newdata.args)); 878 if (rc != 0) 867 if (rc != 0) 879 868 return (unative_t) rc; 880 869 881 870 return sys_ipc_forward_common(callid, phoneid, 882 871 IPC_GET_METHOD(newdata), IPC_GET_ARG1(newdata), … … 890 879 * than the generic sys_ipc_answer(). 891 880 * 892 * @param callid Hash of the call to be answered. 893 * @param retval Return value of the answer. 894 * @param arg1 Service-defined return value. 895 * @param arg2 Service-defined return value. 896 * @param arg3 Service-defined return value. 897 * @param arg4 Service-defined return value. 898 * 899 * @return 0 on success, otherwise an error code. 900 * 881 * @param callid Hash of the call to be answered. 882 * @param retval Return value of the answer. 883 * @param arg1 Service-defined return value. 884 * @param arg2 Service-defined return value. 885 * @param arg3 Service-defined return value. 886 * @param arg4 Service-defined return value. 887 * 888 * @return Return 0 on success, otherwise return an error code. 901 889 */ 902 890 unative_t sys_ipc_answer_fast(unative_t callid, unative_t retval, 903 891 unative_t arg1, unative_t arg2, unative_t arg3, unative_t arg4) 904 892 { 893 call_t *call; 894 ipc_data_t saved_data; 895 int saveddata = 0; 896 int rc; 897 905 898 /* Do not answer notification callids */ 906 899 if (callid & IPC_CALLID_NOTIFICATION) 907 900 return 0; 908 909 call _t *call= get_call(callid);901 902 call = get_call(callid); 910 903 if (!call) 911 904 return ENOENT; 912 913 ipc_data_t saved_data; 914 bool saved; 915 905 916 906 if (answer_need_old(call)) { 917 907 memcpy(&saved_data, &call->data, sizeof(call->data)); 918 saved = true; 919 } else 920 saved = false; 921 908 saveddata = 1; 909 } 910 922 911 IPC_SET_RETVAL(call->data, retval); 923 912 IPC_SET_ARG1(call->data, arg1); … … 925 914 IPC_SET_ARG3(call->data, arg3); 926 915 IPC_SET_ARG4(call->data, arg4); 927 928 916 /* 929 917 * To achieve deterministic behavior, zero out arguments that are beyond … … 931 919 */ 932 920 IPC_SET_ARG5(call->data, 0); 933 int rc = answer_preprocess(call, saved? &saved_data : NULL);934 921 rc = answer_preprocess(call, saveddata ? &saved_data : NULL); 922 935 923 ipc_answer(&TASK->answerbox, call); 936 924 return rc; … … 939 927 /** Answer an IPC call. 940 928 * 941 * @param callid Hash of the call to be answered. 942 * @param data Userspace address of call data with the answer. 943 * 944 * @return 0 on success, otherwise an error code. 945 * 929 * @param callid Hash of the call to be answered. 930 * @param data Userspace address of call data with the answer. 931 * 932 * @return Return 0 on success, otherwise return an error code. 946 933 */ 947 934 unative_t sys_ipc_answer_slow(unative_t callid, ipc_data_t *data) 948 935 { 936 call_t *call; 937 ipc_data_t saved_data; 938 int saveddata = 0; 939 int rc; 940 949 941 /* Do not answer notification callids */ 950 942 if (callid & IPC_CALLID_NOTIFICATION) 951 943 return 0; 952 953 call _t *call= get_call(callid);944 945 call = get_call(callid); 954 946 if (!call) 955 947 return ENOENT; 956 957 ipc_data_t saved_data; 958 bool saved; 959 948 960 949 if (answer_need_old(call)) { 961 950 memcpy(&saved_data, &call->data, sizeof(call->data)); 962 saved = true; 963 } else 964 saved = false; 965 966 int rc = copy_from_uspace(&call->data.args, &data->args, 951 saveddata = 1; 952 } 953 rc = copy_from_uspace(&call->data.args, &data->args, 967 954 sizeof(call->data.args)); 968 955 if (rc != 0) 969 956 return rc; 970 971 rc = answer_preprocess(call, saved ? &saved_data : NULL);957 958 rc = answer_preprocess(call, saveddata ? &saved_data : NULL); 972 959 973 960 ipc_answer(&TASK->answerbox, call); 961 974 962 return rc; 975 963 } … … 977 965 /** Hang up a phone. 978 966 * 979 * @param Phone handle of the phone to be hung up. 980 * 981 * @return 0 on success or an error code. 982 * 967 * @param Phone handle of the phone to be hung up. 968 * 969 * @return Return 0 on success or an error code. 983 970 */ 984 971 unative_t sys_ipc_hangup(unative_t phoneid) 985 972 { 986 973 phone_t *phone; 987 974 988 975 if (phone_get(phoneid, &phone) != EOK) 989 976 return ENOENT; 990 977 991 978 if (ipc_phone_hangup(phone)) 992 979 return -1; 993 980 994 981 return 0; 995 982 } … … 997 984 /** Wait for an incoming IPC call or an answer. 998 985 * 999 * @param calldata Pointer to buffer where the call/answer data is stored. 1000 * @param usec Timeout. See waitq_sleep_timeout() for explanation. 1001 * @param flags Select mode of sleep operation. See waitq_sleep_timeout() 1002 * for explanation. 1003 * 1004 * @return Hash of the call. 1005 * If IPC_CALLID_NOTIFICATION bit is set in the hash, the 1006 * call is a notification. IPC_CALLID_ANSWERED denotes an 1007 * answer. 1008 * 1009 */ 1010 unative_t sys_ipc_wait_for_call(ipc_data_t *calldata, uint32_t usec, 1011 unsigned int flags) 986 * @param calldata Pointer to buffer where the call/answer data is stored. 987 * @param usec Timeout. See waitq_sleep_timeout() for explanation. 988 * @param flags Select mode of sleep operation. See waitq_sleep_timeout() 989 * for explanation. 990 * 991 * @return Hash of the call. 992 * If IPC_CALLID_NOTIFICATION bit is set in the hash, the 993 * call is a notification. IPC_CALLID_ANSWERED denotes an 994 * answer. 995 */ 996 unative_t sys_ipc_wait_for_call(ipc_data_t *calldata, uint32_t usec, int flags) 1012 997 { 1013 998 call_t *call; 1014 999 1015 1000 restart: 1016 1001 1017 1002 #ifdef CONFIG_UDEBUG 1018 1003 udebug_stoppable_begin(); 1019 #endif 1020 1004 #endif 1021 1005 call = ipc_wait_for_call(&TASK->answerbox, usec, 1022 1006 flags | SYNCH_FLAGS_INTERRUPTIBLE); 1023 1007 1024 1008 #ifdef CONFIG_UDEBUG 1025 1009 udebug_stoppable_end(); 1026 1010 #endif 1027 1028 1011 if (!call) 1029 1012 return 0; 1030 1013 1031 1014 if (call->flags & IPC_CALL_NOTIF) { 1032 1015 /* Set in_phone_hash to the interrupt counter */ … … 1034 1017 1035 1018 STRUCT_TO_USPACE(calldata, &call->data); 1036 1019 1037 1020 ipc_call_free(call); 1038 1021 1039 1022 return ((unative_t) call) | IPC_CALLID_NOTIFICATION; 1040 1023 } 1041 1024 1042 1025 if (call->flags & IPC_CALL_ANSWERED) { 1043 1026 process_answer(call); 1044 1027 1045 1028 if (call->flags & IPC_CALL_DISCARD_ANSWER) { 1046 1029 ipc_call_free(call); … … 1054 1037 atomic_dec(&TASK->active_calls); 1055 1038 } 1056 1039 1057 1040 STRUCT_TO_USPACE(&calldata->args, &call->data.args); 1058 1041 ipc_call_free(call); 1059 1042 1060 1043 return ((unative_t) call) | IPC_CALLID_ANSWERED; 1061 1044 } 1062 1045 1063 1046 if (process_request(&TASK->answerbox, call)) 1064 1047 goto restart; 1065 1048 1066 1049 /* Include phone address('id') of the caller in the request, 1067 1050 * copy whole call->data, not only call->data.args */ … … 1072 1055 */ 1073 1056 ipc_data_t saved_data; 1074 bool saved;1075 1057 int saveddata = 0; 1058 1076 1059 if (answer_need_old(call)) { 1077 1060 memcpy(&saved_data, &call->data, sizeof(call->data)); 1078 saved = true; 1079 } else 1080 saved = false; 1061 saveddata = 1; 1062 } 1081 1063 1082 1064 IPC_SET_RETVAL(call->data, EPARTY); 1083 (void) answer_preprocess(call, saved ? &saved_data : NULL);1065 (void) answer_preprocess(call, saveddata ? &saved_data : NULL); 1084 1066 ipc_answer(&TASK->answerbox, call); 1085 1067 return 0; 1086 1068 } 1087 1088 return (unative_t) call; 1089 } 1090 1091 /** Interrupt one thread from sys_ipc_wait_for_call(). 1092 * 1093 */ 1069 return (unative_t)call; 1070 } 1071 1072 /** Interrupt one thread from sys_ipc_wait_for_call(). */ 1094 1073 unative_t sys_ipc_poke(void) 1095 1074 { 1096 waitq_unsleep(&TASK->answerbox.wq); 1075 waitq_unsleep(&TASK->answerbox.wq); 1097 1076 return EOK; 1098 1077 } … … 1100 1079 /** Connect an IRQ handler to a task. 1101 1080 * 1102 * @param inr IRQ number. 1103 * @param devno Device number. 1104 * @param method Method to be associated with the notification. 1105 * @param ucode Uspace pointer to the top-half pseudocode. 1106 * 1107 * @return EPERM or a return code returned by ipc_irq_register(). 1108 * 1081 * @param inr IRQ number. 1082 * @param devno Device number. 1083 * @param method Method to be associated with the notification. 1084 * @param ucode Uspace pointer to the top-half pseudocode. 1085 * 1086 * @return EPERM or a return code returned by ipc_irq_register(). 1109 1087 */ 1110 1088 unative_t sys_ipc_register_irq(inr_t inr, devno_t devno, unative_t method, … … 1113 1091 if (!(cap_get(TASK) & CAP_IRQ_REG)) 1114 1092 return EPERM; 1115 1093 1116 1094 return ipc_irq_register(&TASK->answerbox, inr, devno, method, ucode); 1117 1095 } … … 1119 1097 /** Disconnect an IRQ handler from a task. 1120 1098 * 1121 * @param inr IRQ number. 1122 * @param devno Device number. 1123 * 1124 * @return Zero on success or EPERM on error. 1125 * 1099 * @param inr IRQ number. 1100 * @param devno Device number. 1101 * 1102 * @return Zero on success or EPERM on error.. 1126 1103 */ 1127 1104 unative_t sys_ipc_unregister_irq(inr_t inr, devno_t devno) … … 1129 1106 if (!(cap_get(TASK) & CAP_IRQ_REG)) 1130 1107 return EPERM; 1131 1108 1132 1109 ipc_irq_unregister(&TASK->answerbox, inr, devno); 1133 1110 1134 1111 return 0; 1135 1112 } … … 1137 1114 #include <console/console.h> 1138 1115 1139 /** Syscall connect to a task by id.1140 * 1141 * @return Phone id on success, or negative error code.1142 * 1116 /** 1117 * Syscall connect to a task by id. 1118 * 1119 * @return Phone id on success, or negative error code. 1143 1120 */ 1144 1121 unative_t sys_ipc_connect_kbox(sysarg64_t *uspace_taskid_arg) … … 1146 1123 #ifdef CONFIG_UDEBUG 1147 1124 sysarg64_t taskid_arg; 1148 int rc = copy_from_uspace(&taskid_arg, uspace_taskid_arg, sizeof(sysarg64_t)); 1125 int rc; 1126 1127 rc = copy_from_uspace(&taskid_arg, uspace_taskid_arg, sizeof(sysarg64_t)); 1149 1128 if (rc != 0) 1150 1129 return (unative_t) rc; 1151 1152 LOG("sys_ipc_connect_kbox(%" PRIu64 ") ", taskid_arg.value);1153 1130 1131 LOG("sys_ipc_connect_kbox(%" PRIu64 ")\n", taskid_arg.value); 1132 1154 1133 return ipc_connect_kbox(taskid_arg.value); 1155 1134 #else
Note:
See TracChangeset
for help on using the changeset viewer.