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