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