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