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