- Timestamp:
- 2012-10-15T16:28:58Z (13 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- b3ab8f7
- Parents:
- 7eb49f4 (diff), c4c2406 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - Location:
- kernel
- Files:
-
- 13 added
- 18 edited
Legend:
- Unmodified
- Added
- Removed
-
kernel/Makefile
r7eb49f4 re2a6b72 257 257 generic/src/ipc/ipc.c \ 258 258 generic/src/ipc/sysipc.c \ 259 generic/src/ipc/sysipc_ops.c \ 260 generic/src/ipc/ops/clnestab.c \ 261 generic/src/ipc/ops/conctmeto.c \ 262 generic/src/ipc/ops/concttome.c \ 263 generic/src/ipc/ops/connclone.c \ 264 generic/src/ipc/ops/dataread.c \ 265 generic/src/ipc/ops/datawrite.c \ 266 generic/src/ipc/ops/debug.c \ 267 generic/src/ipc/ops/sharein.c \ 268 generic/src/ipc/ops/shareout.c \ 269 generic/src/ipc/ops/stchngath.c \ 259 270 generic/src/ipc/ipcrsc.c \ 260 271 generic/src/ipc/irq.c \ -
kernel/genarch/include/drivers/arm926_uart/arm926_uart.h
r7eb49f4 re2a6b72 35 35 */ 36 36 37 #ifndef KERN_ S3C24XX_UART_H_38 #define KERN_ S3C24XX_UART_H_37 #ifndef KERN_ARM926_UART_H_ 38 #define KERN_ARM926_UART_H_ 39 39 40 40 #include <ddi/irq.h> -
kernel/genarch/include/multiboot/multiboot.h
r7eb49f4 re2a6b72 99 99 100 100 extern void multiboot_extract_command(char *, size_t, const char *); 101 extern void multiboot_extract_argument(char *, size_t, const char *); 101 102 extern void multiboot_info_parse(uint32_t, const multiboot_info_t *); 102 103 -
kernel/genarch/src/multiboot/multiboot.c
r7eb49f4 re2a6b72 71 71 } 72 72 73 /** Extract arguments from the multiboot module command line. 74 * 75 * @param buf Destination buffer (will be always NULL-terminated). 76 * @param size Size of destination buffer (in bytes). 77 * @param cmd_line Input string (the command line). 78 * 79 */ 80 void multiboot_extract_argument(char *buf, size_t size, const char *cmd_line) 81 { 82 /* Start after first space. */ 83 const char *start = str_chr(cmd_line, ' '); 84 if (start == NULL) { 85 str_cpy(buf, size, ""); 86 return; 87 } 88 89 const char *end = cmd_line + str_size(cmd_line); 90 91 /* Skip the space(s). */ 92 while (start != end) { 93 if (start[0] == ' ') 94 start++; 95 else 96 break; 97 } 98 99 str_ncpy(buf, size, start, (size_t) (end - start)); 100 } 101 73 102 static void multiboot_modules(uint32_t count, multiboot_module_t *mods) 74 103 { … … 84 113 multiboot_extract_command(init.tasks[init.cnt].name, 85 114 CONFIG_TASK_NAME_BUFLEN, MULTIBOOT_PTR(mods[i].string)); 86 } else 115 multiboot_extract_argument(init.tasks[init.cnt].arguments, 116 CONFIG_TASK_ARGUMENTS_BUFLEN, MULTIBOOT_PTR(mods[i].string)); 117 } else { 87 118 init.tasks[init.cnt].name[0] = 0; 119 init.tasks[init.cnt].arguments[0] = 0; 120 } 88 121 89 122 init.cnt++; -
kernel/genarch/src/multiboot/multiboot2.c
r7eb49f4 re2a6b72 49 49 multiboot_extract_command(init.tasks[init.cnt].name, 50 50 CONFIG_TASK_NAME_BUFLEN, module->string); 51 multiboot_extract_argument(init.tasks[init.cnt].arguments, 52 CONFIG_TASK_ARGUMENTS_BUFLEN, module->string); 51 53 52 54 init.cnt++; -
kernel/generic/include/config.h
r7eb49f4 re2a6b72 47 47 #define CONFIG_INIT_TASKS 32 48 48 #define CONFIG_TASK_NAME_BUFLEN 32 49 #define CONFIG_TASK_ARGUMENTS_BUFLEN 64 50 51 /** 52 * Maximum buffer size allowed for IPC_M_DATA_WRITE and IPC_M_DATA_READ 53 * requests. 54 */ 55 #define DATA_XFER_LIMIT (64 * 1024) 49 56 50 57 #ifndef __ASM__ … … 56 63 size_t size; 57 64 char name[CONFIG_TASK_NAME_BUFLEN]; 65 char arguments[CONFIG_TASK_ARGUMENTS_BUFLEN]; 58 66 } init_task_t; 59 67 -
kernel/generic/include/ipc/ipc.h
r7eb49f4 re2a6b72 65 65 mutex_t lock; 66 66 link_t link; 67 struct task *caller; 67 68 struct answerbox *callee; 68 69 ipc_phone_state_t state; … … 72 73 typedef struct answerbox { 73 74 IRQ_SPINLOCK_DECLARE(lock); 75 76 /** Answerbox is active until it enters cleanup. */ 77 bool active; 74 78 75 79 struct task *task; … … 106 110 107 111 typedef struct { 108 link_t link; 112 /** 113 * Task link. 114 * Valid only when the call is not forgotten. 115 * Protected by the task's active_calls_lock. 116 */ 117 link_t ta_link; 118 119 atomic_t refcnt; 120 121 /** Answerbox link. */ 122 link_t ab_link; 109 123 110 124 unsigned int flags; 125 126 /** Protects the forget member. */ 127 SPINLOCK_DECLARE(forget_lock); 128 129 /** 130 * True if the caller 'forgot' this call and donated it to the callee. 131 * Forgotten calls are discarded upon answering (the answer is not 132 * delivered) and answered calls cannot be forgotten. Forgotten calls 133 * also do not figure on the task's active call list. 134 * 135 * We keep this separate from the flags so that it is not necessary 136 * to take a lock when accessing them. 137 */ 138 bool forget; 139 140 /** True if the call is in the active list. */ 141 bool active; 111 142 112 /** Identification of the caller. */ 143 /** 144 * Identification of the caller. 145 * Valid only when the call is not forgotten. 146 */ 113 147 struct task *sender; 148 149 /** Phone which was used to send the call. */ 150 phone_t *caller_phone; 114 151 115 152 /** Private data to internal IPC. */ … … 118 155 /** Data passed from/to userspace. */ 119 156 ipc_data_t data; 120 157 158 /** Method as it was sent in the request. */ 159 sysarg_t request_method; 160 121 161 /** Buffer for IPC_M_DATA_WRITE and IPC_M_DATA_READ. */ 122 162 uint8_t *buffer; 123 124 /*125 * The forward operation can masquerade the caller phone. For those126 * cases, we must keep it aside so that the answer is processed127 * correctly.128 */129 phone_t *caller_phone;130 163 } call_t; 131 164 … … 136 169 extern call_t *ipc_call_alloc(unsigned int); 137 170 extern void ipc_call_free(call_t *); 171 extern void ipc_call_hold(call_t *); 172 extern void ipc_call_release(call_t *); 138 173 139 174 extern int ipc_call(phone_t *, call_t *); … … 141 176 extern int ipc_forward(call_t *, phone_t *, answerbox_t *, unsigned int); 142 177 extern void ipc_answer(answerbox_t *, call_t *); 178 extern void _ipc_answer_free_call(call_t *, bool); 143 179 144 extern void ipc_phone_init(phone_t * );145 extern voidipc_phone_connect(phone_t *, answerbox_t *);180 extern void ipc_phone_init(phone_t *, struct task *); 181 extern bool ipc_phone_connect(phone_t *, answerbox_t *); 146 182 extern int ipc_phone_hangup(phone_t *); 147 183 … … 151 187 extern void ipc_backsend_err(phone_t *, call_t *, sysarg_t); 152 188 extern void ipc_answerbox_slam_phones(answerbox_t *, bool); 153 extern void ipc_cleanup_call_list( list_t *);189 extern void ipc_cleanup_call_list(answerbox_t *, list_t *); 154 190 155 191 extern void ipc_print_task(task_id_t); -
kernel/generic/include/ipc/ipcrsc.h
r7eb49f4 re2a6b72 40 40 41 41 extern call_t *get_call(sysarg_t); 42 extern int phone_get(sysarg_t, phone_t **); 42 43 extern int phone_alloc(task_t *); 43 extern voidphone_connect(int, answerbox_t *);44 extern bool phone_connect(int, answerbox_t *); 44 45 extern void phone_dealloc(int); 45 46 -
kernel/generic/include/proc/task.h
r7eb49f4 re2a6b72 91 91 92 92 /* IPC stuff */ 93 answerbox_t answerbox; /**< Communication endpoint */ 93 94 /** Receiving communication endpoint */ 95 answerbox_t answerbox; 96 97 /** Sending communication endpoints */ 94 98 phone_t phones[IPC_MAX_PHONES]; 95 stats_ipc_t ipc_info; /**< IPC statistics */ 99 100 /** Spinlock protecting the active_calls list. */ 101 SPINLOCK_DECLARE(active_calls_lock); 102 103 /** 104 * List of all calls sent by this task that have not yet been 105 * answered. 106 */ 107 list_t active_calls; 108 96 109 event_t events[EVENT_TASK_END - EVENT_END]; 110 111 /** IPC statistics */ 112 stats_ipc_t ipc_info; 97 113 98 114 #ifdef CONFIG_UDEBUG -
kernel/generic/src/ipc/event.c
r7eb49f4 re2a6b72 163 163 call->data.task_id = TASK ? TASK->taskid : 0; 164 164 165 irq_spinlock_lock(&event->answerbox->irq_lock, true); 166 list_append(&call->link, &event->answerbox->irq_notifs); 167 irq_spinlock_unlock(&event->answerbox->irq_lock, true); 168 169 waitq_wakeup(&event->answerbox->wq, WAKEUP_FIRST); 165 irq_spinlock_lock(&event->answerbox->irq_lock, 166 true); 167 list_append(&call->ab_link, 168 &event->answerbox->irq_notifs); 169 irq_spinlock_unlock(&event->answerbox->irq_lock, 170 true); 171 172 waitq_wakeup(&event->answerbox->wq, 173 WAKEUP_FIRST); 170 174 171 175 if (mask) -
kernel/generic/src/ipc/ipc.c
r7eb49f4 re2a6b72 45 45 #include <ipc/kbox.h> 46 46 #include <ipc/event.h> 47 #include <ipc/sysipc_ops.h> 48 #include <ipc/sysipc_priv.h> 47 49 #include <errno.h> 48 50 #include <mm/slab.h> … … 71 73 { 72 74 memsetb(call, sizeof(*call), 0); 73 call->sender = TASK; 75 spinlock_initialize(&call->forget_lock, "forget_lock"); 76 call->active = false; 77 call->forget = false; 78 call->sender = NULL; 74 79 call->buffer = NULL; 80 } 81 82 void ipc_call_hold(call_t *call) 83 { 84 atomic_inc(&call->refcnt); 85 } 86 87 void ipc_call_release(call_t *call) 88 { 89 if (atomic_predec(&call->refcnt) == 0) { 90 if (call->buffer) 91 free(call->buffer); 92 slab_free(ipc_call_slab, call); 93 } 75 94 } 76 95 … … 83 102 * 84 103 * @return If flags permit it, return NULL, or initialized kernel 85 * call structure .104 * call structure with one reference. 86 105 * 87 106 */ … … 89 108 { 90 109 call_t *call = slab_alloc(ipc_call_slab, flags); 91 if (call) 110 if (call) { 92 111 _ipc_call_init(call); 112 ipc_call_hold(call); 113 } 93 114 94 115 return call; … … 102 123 void ipc_call_free(call_t *call) 103 124 { 104 /* Check to see if we have data in the IPC_M_DATA_SEND buffer. */ 105 if (call->buffer) 106 free(call->buffer); 107 slab_free(ipc_call_slab, call); 125 ipc_call_release(call); 108 126 } 109 127 … … 132 150 * @param phone Initialized phone structure. 133 151 * @param box Initialized answerbox structure. 134 * 135 */ 136 void ipc_phone_connect(phone_t *phone, answerbox_t *box) 137 { 152 * @return True if the phone was connected, false otherwise. 153 */ 154 bool ipc_phone_connect(phone_t *phone, answerbox_t *box) 155 { 156 bool active; 157 138 158 mutex_lock(&phone->lock); 139 140 phone->state = IPC_PHONE_CONNECTED;141 phone->callee = box;142 143 159 irq_spinlock_lock(&box->lock, true); 144 list_append(&phone->link, &box->connected_phones); 160 161 active = box->active; 162 if (active) { 163 phone->state = IPC_PHONE_CONNECTED; 164 phone->callee = box; 165 list_append(&phone->link, &box->connected_phones); 166 } 167 145 168 irq_spinlock_unlock(&box->lock, true); 146 147 169 mutex_unlock(&phone->lock); 170 171 return active; 148 172 } 149 173 … … 151 175 * 152 176 * @param phone Phone structure to be initialized. 153 * 154 */ 155 void ipc_phone_init(phone_t *phone) 177 * @param caller Owning task. 178 * 179 */ 180 void ipc_phone_init(phone_t *phone, task_t *caller) 156 181 { 157 182 mutex_initialize(&phone->lock, MUTEX_PASSIVE); 183 phone->caller = caller; 158 184 phone->callee = NULL; 159 185 phone->state = IPC_PHONE_FREE; … … 167 193 * 168 194 */ 169 static void _ipc_answer_free_call(call_t *call, bool selflocked) 170 { 171 answerbox_t *callerbox = &call->sender->answerbox; 172 bool do_lock = ((!selflocked) || callerbox != (&TASK->answerbox)); 173 195 void _ipc_answer_free_call(call_t *call, bool selflocked) 196 { 174 197 /* Count sent answer */ 175 198 irq_spinlock_lock(&TASK->lock, true); 176 199 TASK->ipc_info.answer_sent++; 177 200 irq_spinlock_unlock(&TASK->lock, true); 201 202 spinlock_lock(&call->forget_lock); 203 if (call->forget) { 204 /* This is a forgotten call and call->sender is not valid. */ 205 spinlock_unlock(&call->forget_lock); 206 ipc_call_free(call); 207 return; 208 } else { 209 /* 210 * If the call is still active, i.e. it was answered 211 * in a non-standard way, remove the call from the 212 * sender's active call list. 213 */ 214 if (call->active) { 215 spinlock_lock(&call->sender->active_calls_lock); 216 list_remove(&call->ta_link); 217 spinlock_unlock(&call->sender->active_calls_lock); 218 } 219 } 220 spinlock_unlock(&call->forget_lock); 221 222 answerbox_t *callerbox = &call->sender->answerbox; 223 bool do_lock = ((!selflocked) || (callerbox != &TASK->answerbox)); 178 224 179 225 call->flags |= IPC_CALL_ANSWERED; 180 226 181 if (call->flags & IPC_CALL_FORWARDED) {182 if (call->caller_phone) {183 /* Demasquerade the caller phone. */184 call->data.phone = call->caller_phone;185 }186 }187 188 227 call->data.task_id = TASK->taskid; 189 228 … … 191 230 irq_spinlock_lock(&callerbox->lock, true); 192 231 193 list_append(&call-> link, &callerbox->answers);232 list_append(&call->ab_link, &callerbox->answers); 194 233 195 234 if (do_lock) … … 209 248 /* Remove from active box */ 210 249 irq_spinlock_lock(&box->lock, true); 211 list_remove(&call-> link);250 list_remove(&call->ab_link); 212 251 irq_spinlock_unlock(&box->lock, true); 213 252 214 253 /* Send back answer */ 215 254 _ipc_answer_free_call(call, false); 255 } 256 257 static void _ipc_call_actions_internal(phone_t *phone, call_t *call) 258 { 259 task_t *caller = phone->caller; 260 261 atomic_inc(&phone->active_calls); 262 call->caller_phone = phone; 263 call->sender = caller; 264 265 call->active = true; 266 spinlock_lock(&caller->active_calls_lock); 267 list_append(&call->ta_link, &caller->active_calls); 268 spinlock_unlock(&caller->active_calls_lock); 269 270 call->data.phone = phone; 271 call->data.task_id = caller->taskid; 216 272 } 217 273 … … 228 284 void ipc_backsend_err(phone_t *phone, call_t *call, sysarg_t err) 229 285 { 230 call->data.phone = phone; 231 atomic_inc(&phone->active_calls); 286 _ipc_call_actions_internal(phone, call); 232 287 IPC_SET_RETVAL(call->data, err); 233 288 _ipc_answer_free_call(call, false); … … 243 298 static void _ipc_call(phone_t *phone, answerbox_t *box, call_t *call) 244 299 { 300 task_t *caller = phone->caller; 301 245 302 /* Count sent ipc call */ 246 irq_spinlock_lock(&TASK->lock, true); 247 TASK->ipc_info.call_sent++; 248 irq_spinlock_unlock(&TASK->lock, true); 249 250 if (!(call->flags & IPC_CALL_FORWARDED)) { 251 atomic_inc(&phone->active_calls); 252 call->data.phone = phone; 253 call->data.task_id = TASK->taskid; 254 } 303 irq_spinlock_lock(&caller->lock, true); 304 caller->ipc_info.call_sent++; 305 irq_spinlock_unlock(&caller->lock, true); 306 307 if (!(call->flags & IPC_CALL_FORWARDED)) 308 _ipc_call_actions_internal(phone, call); 255 309 256 310 irq_spinlock_lock(&box->lock, true); 257 list_append(&call-> link, &box->calls);311 list_append(&call->ab_link, &box->calls); 258 312 irq_spinlock_unlock(&box->lock, true); 259 313 … … 275 329 if (phone->state != IPC_PHONE_CONNECTED) { 276 330 mutex_unlock(&phone->lock); 277 if (call->flags & IPC_CALL_FORWARDED) { 278 IPC_SET_RETVAL(call->data, EFORWARD); 279 _ipc_answer_free_call(call, false); 280 } else { 331 if (!(call->flags & IPC_CALL_FORWARDED)) { 281 332 if (phone->state == IPC_PHONE_HUNGUP) 282 333 ipc_backsend_err(phone, call, EHANGUP); … … 325 376 call_t *call = ipc_call_alloc(0); 326 377 IPC_SET_IMETHOD(call->data, IPC_M_PHONE_HUNGUP); 378 call->request_method = IPC_M_PHONE_HUNGUP; 327 379 call->flags |= IPC_CALL_DISCARD_ANSWER; 328 380 _ipc_call(phone, box, call); … … 356 408 TASK->ipc_info.forwarded++; 357 409 irq_spinlock_pass(&TASK->lock, &oldbox->lock); 358 list_remove(&call-> link);410 list_remove(&call->ab_link); 359 411 irq_spinlock_unlock(&oldbox->lock, true); 360 412 361 413 if (mode & IPC_FF_ROUTE_FROM_ME) { 362 if (!call->caller_phone)363 call->caller_phone = call->data.phone;364 414 call->data.phone = newphone; 365 415 call->data.task_id = TASK->taskid; … … 406 456 407 457 request = list_get_instance(list_first(&box->irq_notifs), 408 call_t, link);409 list_remove(&request-> link);458 call_t, ab_link); 459 list_remove(&request->ab_link); 410 460 411 461 irq_spinlock_unlock(&box->irq_lock, false); … … 416 466 /* Handle asynchronous answers */ 417 467 request = list_get_instance(list_first(&box->answers), 418 call_t, link);419 list_remove(&request-> link);420 atomic_dec(&request-> data.phone->active_calls);468 call_t, ab_link); 469 list_remove(&request->ab_link); 470 atomic_dec(&request->caller_phone->active_calls); 421 471 } else if (!list_empty(&box->calls)) { 422 472 /* Count received call */ … … 425 475 /* Handle requests */ 426 476 request = list_get_instance(list_first(&box->calls), 427 call_t, link);428 list_remove(&request-> link);477 call_t, ab_link); 478 list_remove(&request->ab_link); 429 479 430 480 /* Append request to dispatch queue */ 431 list_append(&request-> link, &box->dispatched_calls);481 list_append(&request->ab_link, &box->dispatched_calls); 432 482 } else { 433 483 /* This can happen regularly after ipc_cleanup */ … … 449 499 /** Answer all calls from list with EHANGUP answer. 450 500 * 501 * @param box Answerbox with the list. 451 502 * @param lst Head of the list to be cleaned up. 452 * 453 */ 454 void ipc_cleanup_call_list(list_t *lst) 455 { 503 */ 504 void ipc_cleanup_call_list(answerbox_t *box, list_t *lst) 505 { 506 irq_spinlock_lock(&box->lock, true); 456 507 while (!list_empty(lst)) { 457 call_t *call = list_get_instance(list_first(lst), call_t, link); 458 if (call->buffer) 459 free(call->buffer); 460 461 list_remove(&call->link); 462 508 call_t *call = list_get_instance(list_first(lst), call_t, 509 ab_link); 510 511 list_remove(&call->ab_link); 512 513 irq_spinlock_unlock(&box->lock, true); 514 515 if (lst == &box->calls) 516 SYSIPC_OP(request_process, call, box); 517 518 ipc_data_t old = call->data; 463 519 IPC_SET_RETVAL(call->data, EHANGUP); 520 answer_preprocess(call, &old); 464 521 _ipc_answer_free_call(call, true); 465 } 522 523 irq_spinlock_lock(&box->lock, true); 524 } 525 irq_spinlock_unlock(&box->lock, true); 466 526 } 467 527 … … 501 561 mutex_unlock(&phone->lock); 502 562 irq_spinlock_unlock(&box->lock, true); 503 563 564 // FIXME: phone can become deallocated at any time now 565 504 566 /* 505 567 * Send one message to the answerbox for each … … 509 571 */ 510 572 IPC_SET_IMETHOD(call->data, IPC_M_PHONE_HUNGUP); 573 call->request_method = IPC_M_PHONE_HUNGUP; 511 574 call->flags |= IPC_CALL_DISCARD_ANSWER; 512 575 _ipc_call(phone, box, call); … … 529 592 } 530 593 594 static void ipc_forget_all_active_calls(void) 595 { 596 call_t *call; 597 598 restart: 599 spinlock_lock(&TASK->active_calls_lock); 600 if (list_empty(&TASK->active_calls)) { 601 /* 602 * We are done, there are no more active calls. 603 * Nota bene: there may still be answers waiting for pick up. 604 */ 605 spinlock_unlock(&TASK->active_calls_lock); 606 return; 607 } 608 609 call = list_get_instance(list_first(&TASK->active_calls), call_t, 610 ta_link); 611 612 if (!spinlock_trylock(&call->forget_lock)) { 613 /* 614 * Avoid deadlock and let async_answer() or 615 * _ipc_answer_free_call() win the race to dequeue the first 616 * call on the list. 617 */ 618 spinlock_unlock(&TASK->active_calls_lock); 619 goto restart; 620 } 621 622 /* 623 * Forget the call and donate it to the task which holds up the answer. 624 */ 625 626 call->forget = true; 627 call->sender = NULL; 628 list_remove(&call->ta_link); 629 630 /* 631 * The call may be freed by _ipc_answer_free_call() before we are done 632 * with it; to avoid working with a destroyed call_t structure, we 633 * must hold a reference to it. 634 */ 635 ipc_call_hold(call); 636 637 spinlock_unlock(&call->forget_lock); 638 spinlock_unlock(&TASK->active_calls_lock); 639 640 atomic_dec(&call->caller_phone->active_calls); 641 642 SYSIPC_OP(request_forget, call); 643 644 ipc_call_release(call); 645 646 goto restart; 647 } 648 649 /** Wait for all answers to asynchronous calls to arrive. */ 650 static void ipc_wait_for_all_answered_calls(void) 651 { 652 call_t *call; 653 size_t i; 654 655 restart: 656 /* 657 * Go through all phones, until they are all free. 658 * Locking is needed as there may be connection handshakes in progress. 659 */ 660 for (i = 0; i < IPC_MAX_PHONES; i++) { 661 phone_t *phone = &TASK->phones[i]; 662 663 mutex_lock(&phone->lock); 664 if ((phone->state == IPC_PHONE_HUNGUP) && 665 (atomic_get(&phone->active_calls) == 0)) { 666 phone->state = IPC_PHONE_FREE; 667 phone->callee = NULL; 668 } 669 670 /* 671 * We might have had some IPC_PHONE_CONNECTING phones at the 672 * beginning of ipc_cleanup(). Depending on whether these were 673 * forgotten or answered, they will eventually enter the 674 * IPC_PHONE_FREE or IPC_PHONE_CONNECTED states, respectively. 675 * In the latter case, the other side may slam the open phones 676 * at any time, in which case we will get an IPC_PHONE_SLAMMED 677 * phone. 678 */ 679 if ((phone->state == IPC_PHONE_CONNECTED) || 680 (phone->state == IPC_PHONE_SLAMMED)) { 681 mutex_unlock(&phone->lock); 682 ipc_phone_hangup(phone); 683 /* 684 * Now there may be one extra active call, which needs 685 * to be forgotten. 686 */ 687 ipc_forget_all_active_calls(); 688 goto restart; 689 } 690 691 /* 692 * If the hangup succeeded, it has sent a HANGUP message, the 693 * IPC is now in HUNGUP state, we wait for the reply to come 694 */ 695 if (phone->state != IPC_PHONE_FREE) { 696 mutex_unlock(&phone->lock); 697 break; 698 } 699 700 mutex_unlock(&phone->lock); 701 } 702 703 /* Got into cleanup */ 704 if (i == IPC_MAX_PHONES) 705 return; 706 707 call = ipc_wait_for_call(&TASK->answerbox, SYNCH_NO_TIMEOUT, 708 SYNCH_FLAGS_NONE); 709 ASSERT(call->flags & (IPC_CALL_ANSWERED | IPC_CALL_NOTIF)); 710 711 SYSIPC_OP(answer_process, call); 712 713 ipc_call_free(call); 714 goto restart; 715 } 716 531 717 /** Clean up all IPC communication of the current task. 532 718 * … … 537 723 void ipc_cleanup(void) 538 724 { 725 /* 726 * Mark the answerbox as inactive. 727 * 728 * The main purpose for doing this is to prevent any pending callback 729 * connections from getting established beyond this point. 730 */ 731 irq_spinlock_lock(&TASK->answerbox.lock, true); 732 TASK->answerbox.active = false; 733 irq_spinlock_unlock(&TASK->answerbox.lock, true); 734 539 735 /* Disconnect all our phones ('ipc_phone_hangup') */ 540 size_t i; 541 for (i = 0; i < IPC_MAX_PHONES; i++) 736 for (size_t i = 0; i < IPC_MAX_PHONES; i++) 542 737 ipc_phone_hangup(&TASK->phones[i]); 543 738 … … 557 752 558 753 /* Answer all messages in 'calls' and 'dispatched_calls' queues */ 559 irq_spinlock_lock(&TASK->answerbox.lock, true); 560 ipc_cleanup_call_list(&TASK->answerbox.dispatched_calls); 561 ipc_cleanup_call_list(&TASK->answerbox.calls); 562 irq_spinlock_unlock(&TASK->answerbox.lock, true); 563 564 /* Wait for all answers to asynchronous calls to arrive */ 565 while (true) { 566 /* 567 * Go through all phones, until they are all FREE 568 * Locking is not needed, no one else should modify 569 * it when we are in cleanup 570 */ 571 for (i = 0; i < IPC_MAX_PHONES; i++) { 572 if (TASK->phones[i].state == IPC_PHONE_HUNGUP && 573 atomic_get(&TASK->phones[i].active_calls) == 0) { 574 TASK->phones[i].state = IPC_PHONE_FREE; 575 TASK->phones[i].callee = NULL; 576 } 577 578 /* 579 * Just for sure, we might have had some 580 * IPC_PHONE_CONNECTING phones 581 */ 582 if (TASK->phones[i].state == IPC_PHONE_CONNECTED) 583 ipc_phone_hangup(&TASK->phones[i]); 584 585 /* 586 * If the hangup succeeded, it has sent a HANGUP 587 * message, the IPC is now in HUNGUP state, we 588 * wait for the reply to come 589 */ 590 591 if (TASK->phones[i].state != IPC_PHONE_FREE) 592 break; 593 } 594 595 /* Got into cleanup */ 596 if (i == IPC_MAX_PHONES) 597 break; 598 599 call_t *call = ipc_wait_for_call(&TASK->answerbox, SYNCH_NO_TIMEOUT, 600 SYNCH_FLAGS_NONE); 601 ASSERT((call->flags & IPC_CALL_ANSWERED) || 602 (call->flags & IPC_CALL_NOTIF)); 603 604 ipc_call_free(call); 605 } 754 ipc_cleanup_call_list(&TASK->answerbox, &TASK->answerbox.calls); 755 ipc_cleanup_call_list(&TASK->answerbox, 756 &TASK->answerbox.dispatched_calls); 757 758 ipc_forget_all_active_calls(); 759 ipc_wait_for_all_answered_calls(); 606 760 } 607 761 … … 615 769 ipc_answerbox_slab = slab_cache_create("answerbox_t", 616 770 sizeof(answerbox_t), 0, NULL, NULL, 0); 771 } 772 773 774 static void ipc_print_call_list(list_t *list) 775 { 776 list_foreach(*list, cur) { 777 call_t *call = list_get_instance(cur, call_t, ab_link); 778 779 #ifdef __32_BITS__ 780 printf("%10p ", call); 781 #endif 782 783 #ifdef __64_BITS__ 784 printf("%18p ", call); 785 #endif 786 787 spinlock_lock(&call->forget_lock); 788 789 printf("%-8" PRIun " %-6" PRIun " %-6" PRIun " %-6" PRIun 790 " %-6" PRIun " %-6" PRIun " %-7x", 791 IPC_GET_IMETHOD(call->data), IPC_GET_ARG1(call->data), 792 IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data), 793 IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data), 794 call->flags); 795 796 if (call->forget) { 797 printf(" ? (call forgotten)\n"); 798 } else { 799 printf(" %" PRIu64 " (%s)\n", 800 call->sender->taskid, call->sender->name); 801 } 802 803 spinlock_unlock(&call->forget_lock); 804 } 617 805 } 618 806 … … 688 876 689 877 printf(" --- incomming calls ---\n"); 690 list_foreach(task->answerbox.calls, cur) { 691 call_t *call = list_get_instance(cur, call_t, link); 692 693 #ifdef __32_BITS__ 694 printf("%10p ", call); 695 #endif 696 697 #ifdef __64_BITS__ 698 printf("%18p ", call); 699 #endif 700 701 printf("%-8" PRIun " %-6" PRIun " %-6" PRIun " %-6" PRIun 702 " %-6" PRIun " %-6" PRIun " %-7x %" PRIu64 " (%s)\n", 703 IPC_GET_IMETHOD(call->data), IPC_GET_ARG1(call->data), 704 IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data), 705 IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data), 706 call->flags, call->sender->taskid, call->sender->name); 707 } 708 878 ipc_print_call_list(&task->answerbox.calls); 709 879 printf(" --- dispatched calls ---\n"); 710 list_foreach(task->answerbox.dispatched_calls, cur) { 711 call_t *call = list_get_instance(cur, call_t, link); 712 713 #ifdef __32_BITS__ 714 printf("%10p ", call); 715 #endif 716 717 #ifdef __64_BITS__ 718 printf("%18p ", call); 719 #endif 720 721 printf("%-8" PRIun " %-6" PRIun " %-6" PRIun " %-6" PRIun 722 " %-6" PRIun " %-6" PRIun " %-7x %" PRIu64 " (%s)\n", 723 IPC_GET_IMETHOD(call->data), IPC_GET_ARG1(call->data), 724 IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data), 725 IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data), 726 call->flags, call->sender->taskid, call->sender->name); 727 } 728 880 ipc_print_call_list(&task->answerbox.dispatched_calls); 729 881 printf(" --- incoming answers ---\n"); 730 list_foreach(task->answerbox.answers, cur) { 731 call_t *call = list_get_instance(cur, call_t, link); 732 733 #ifdef __32_BITS__ 734 printf("%10p ", call); 735 #endif 736 737 #ifdef __64_BITS__ 738 printf("%18p ", call); 739 #endif 740 741 printf("%-8" PRIun " %-6" PRIun " %-6" PRIun " %-6" PRIun 742 " %-6" PRIun " %-6" PRIun " %-7x %" PRIu64 " (%s)\n", 743 IPC_GET_IMETHOD(call->data), IPC_GET_ARG1(call->data), 744 IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data), 745 IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data), 746 call->flags, call->sender->taskid, call->sender->name); 747 } 882 ipc_print_call_list(&task->answerbox.answers); 748 883 749 884 irq_spinlock_unlock(&task->answerbox.lock, false); -
kernel/generic/src/ipc/ipcrsc.c
r7eb49f4 re2a6b72 132 132 #include <ipc/ipcrsc.h> 133 133 #include <debug.h> 134 #include <abi/errno.h> 134 135 135 136 /** Find call_t * in call table according to callid. … … 151 152 152 153 list_foreach(TASK->answerbox.dispatched_calls, lst) { 153 call_t *call = list_get_instance(lst, call_t, link);154 call_t *call = list_get_instance(lst, call_t, ab_link); 154 155 if ((sysarg_t) call == callid) { 155 156 result = call; … … 162 163 } 163 164 165 /** Get phone from the current task by ID. 166 * 167 * @param phoneid Phone ID. 168 * @param phone Place to store pointer to phone. 169 * 170 * @return EOK on success, EINVAL if ID is invalid. 171 * 172 */ 173 int phone_get(sysarg_t phoneid, phone_t **phone) 174 { 175 if (phoneid >= IPC_MAX_PHONES) 176 return EINVAL; 177 178 *phone = &TASK->phones[phoneid]; 179 return EOK; 180 } 181 164 182 /** Allocate new phone slot in the specified task. 165 183 * … … 176 194 size_t i; 177 195 for (i = 0; i < IPC_MAX_PHONES; i++) { 178 if ((task->phones[i].state == IPC_PHONE_HUNGUP) && 179 (atomic_get(&task->phones[i].active_calls) == 0)) 180 task->phones[i].state = IPC_PHONE_FREE; 196 phone_t *phone = &task->phones[i]; 197 198 if ((phone->state == IPC_PHONE_HUNGUP) && 199 (atomic_get(&phone->active_calls) == 0)) 200 phone->state = IPC_PHONE_FREE; 181 201 182 if ( task->phones[i].state == IPC_PHONE_FREE) {183 task->phones[i].state = IPC_PHONE_CONNECTING;202 if (phone->state == IPC_PHONE_FREE) { 203 phone->state = IPC_PHONE_CONNECTING; 184 204 break; 185 205 } … … 223 243 * @param phoneid Phone handle to be connected. 224 244 * @param box Answerbox to which to connect the phone handle. 245 * @return True if the phone was connected, false otherwise. 225 246 * 226 247 * The procedure _enforces_ that the user first marks the phone … … 229 250 * 230 251 */ 231 voidphone_connect(int phoneid, answerbox_t *box)252 bool phone_connect(int phoneid, answerbox_t *box) 232 253 { 233 254 phone_t *phone = &TASK->phones[phoneid]; 234 255 235 256 ASSERT(phone->state == IPC_PHONE_CONNECTING); 236 ipc_phone_connect(phone, box);257 return ipc_phone_connect(phone, box); 237 258 } 238 259 -
kernel/generic/src/ipc/irq.c
r7eb49f4 re2a6b72 510 510 { 511 511 irq_spinlock_lock(&irq->notif_cfg.answerbox->irq_lock, false); 512 list_append(&call-> link, &irq->notif_cfg.answerbox->irq_notifs);512 list_append(&call->ab_link, &irq->notif_cfg.answerbox->irq_notifs); 513 513 irq_spinlock_unlock(&irq->notif_cfg.answerbox->irq_lock, false); 514 514 -
kernel/generic/src/ipc/kbox.c
r7eb49f4 re2a6b72 48 48 { 49 49 /* 50 * Not really needed, just to be consistent with the meaning of 51 * answerbox_t.active. 52 */ 53 irq_spinlock_lock(&TASK->kb.box.lock, true); 54 TASK->kb.box.active = false; 55 irq_spinlock_unlock(&TASK->kb.box.lock, true); 56 57 /* 50 58 * Only hold kb.cleanup_lock while setting kb.finished - 51 59 * this is enough. … … 88 96 89 97 /* Answer all messages in 'calls' and 'dispatched_calls' queues. */ 90 irq_spinlock_lock(&TASK->kb.box.lock, true); 91 ipc_cleanup_call_list(&TASK->kb.box.dispatched_calls); 92 ipc_cleanup_call_list(&TASK->kb.box.calls); 93 irq_spinlock_unlock(&TASK->kb.box.lock, true); 98 ipc_cleanup_call_list(&TASK->kb.box, &TASK->kb.box.calls); 99 ipc_cleanup_call_list(&TASK->kb.box, &TASK->kb.box.dispatched_calls); 94 100 } 95 101 … … 162 168 while (!done) { 163 169 call_t *call = ipc_wait_for_call(&TASK->kb.box, SYNCH_NO_TIMEOUT, 164 170 SYNCH_FLAGS_NONE); 165 171 166 172 if (call == NULL) … … 236 242 237 243 /* Connect the newly allocated phone to the kbox */ 238 ipc_phone_connect(&TASK->phones[newphid], &task->kb.box);244 (void) ipc_phone_connect(&TASK->phones[newphid], &task->kb.box); 239 245 240 246 if (task->kb.thread != NULL) { -
kernel/generic/src/ipc/sysipc.c
r7eb49f4 re2a6b72 34 34 35 35 #include <arch.h> 36 #include <proc/task.h>37 #include <proc/thread.h>38 36 #include <errno.h> 39 37 #include <memstr.h> 40 #include <debug.h>41 38 #include <ipc/ipc.h> 42 39 #include <abi/ipc/methods.h> 43 40 #include <ipc/sysipc.h> 41 #include <ipc/sysipc_ops.h> 42 #include <ipc/sysipc_priv.h> 44 43 #include <ipc/irq.h> 45 44 #include <ipc/ipcrsc.h> … … 47 46 #include <ipc/kbox.h> 48 47 #include <synch/waitq.h> 49 #include <udebug/udebug_ipc.h>50 48 #include <arch/interrupt.h> 51 49 #include <syscall/copy.h> 52 50 #include <security/cap.h> 53 51 #include <console/console.h> 54 #include <mm/as.h>55 52 #include <print.h> 56 53 #include <macros.h> 57 54 58 /**59 * Maximum buffer size allowed for IPC_M_DATA_WRITE and IPC_M_DATA_READ60 * requests.61 */62 #define DATA_XFER_LIMIT (64 * 1024)63 64 55 #define STRUCT_TO_USPACE(dst, src) copy_to_uspace((dst), (src), sizeof(*(src))) 65 66 /** Get phone from the current task by ID.67 *68 * @param phoneid Phone ID.69 * @param phone Place to store pointer to phone.70 *71 * @return EOK on success, EINVAL if ID is invalid.72 *73 */74 static int phone_get(sysarg_t phoneid, phone_t **phone)75 {76 if (phoneid >= IPC_MAX_PHONES)77 return EINVAL;78 79 *phone = &TASK->phones[phoneid];80 return EOK;81 }82 56 83 57 /** Decide if the interface and method is a system method. … … 181 155 * @param olddata Saved data of the request. 182 156 * 183 * @return Return 0 on success or an error code. 184 * 185 */ 186 static inline int answer_preprocess(call_t *answer, ipc_data_t *olddata) 187 { 157 * @return Return EOK on success or a negative error code. 158 * 159 */ 160 int answer_preprocess(call_t *answer, ipc_data_t *olddata) 161 { 162 int rc = EOK; 163 164 spinlock_lock(&answer->forget_lock); 165 if (answer->forget) { 166 /* 167 * This is a forgotten call and answer->sender is not valid. 168 */ 169 spinlock_unlock(&answer->forget_lock); 170 171 SYSIPC_OP(answer_cleanup, answer, olddata); 172 return rc; 173 } else { 174 ASSERT(answer->active); 175 176 /* 177 * Mark the call as inactive to prevent _ipc_answer_free_call() 178 * from attempting to remove the call from the active list 179 * itself. 180 */ 181 answer->active = false; 182 183 /* 184 * Remove the call from the sender's active call list. 185 * We enforce this locking order so that any potential 186 * concurrently executing forget operation is forced to 187 * release its active_calls_lock and lose the race to 188 * forget this soon to be answered call. 189 */ 190 spinlock_lock(&answer->sender->active_calls_lock); 191 list_remove(&answer->ta_link); 192 spinlock_unlock(&answer->sender->active_calls_lock); 193 } 194 spinlock_unlock(&answer->forget_lock); 195 188 196 if ((native_t) IPC_GET_RETVAL(answer->data) == EHANGUP) { 189 /* In case of forward, hangup the forwared phone, 190 * not the originator 191 */ 192 mutex_lock(&answer->data.phone->lock); 193 irq_spinlock_lock(&TASK->answerbox.lock, true); 194 if (answer->data.phone->state == IPC_PHONE_CONNECTED) { 195 list_remove(&answer->data.phone->link); 196 answer->data.phone->state = IPC_PHONE_SLAMMED; 197 phone_t *phone = answer->caller_phone; 198 mutex_lock(&phone->lock); 199 if (phone->state == IPC_PHONE_CONNECTED) { 200 irq_spinlock_lock(&phone->callee->lock, true); 201 list_remove(&phone->link); 202 phone->state = IPC_PHONE_SLAMMED; 203 irq_spinlock_unlock(&phone->callee->lock, true); 197 204 } 198 irq_spinlock_unlock(&TASK->answerbox.lock, true); 199 mutex_unlock(&answer->data.phone->lock); 205 mutex_unlock(&phone->lock); 200 206 } 201 207 202 208 if (!olddata) 203 return 0; 204 205 if (IPC_GET_IMETHOD(*olddata) == IPC_M_CONNECTION_CLONE) { 206 int phoneid = IPC_GET_ARG1(*olddata); 207 phone_t *phone = &TASK->phones[phoneid]; 208 209 if (IPC_GET_RETVAL(answer->data) != EOK) { 210 /* 211 * The recipient of the cloned phone rejected the offer. 212 * In this case, the connection was established at the 213 * request time and therefore we need to slam the phone. 214 * We don't merely hangup as that would result in 215 * sending IPC_M_HUNGUP to the third party on the 216 * other side of the cloned phone. 217 */ 218 mutex_lock(&phone->lock); 219 if (phone->state == IPC_PHONE_CONNECTED) { 220 irq_spinlock_lock(&phone->callee->lock, true); 221 list_remove(&phone->link); 222 phone->state = IPC_PHONE_SLAMMED; 223 irq_spinlock_unlock(&phone->callee->lock, true); 224 } 225 mutex_unlock(&phone->lock); 226 } 227 } else if (IPC_GET_IMETHOD(*olddata) == IPC_M_CLONE_ESTABLISH) { 228 phone_t *phone = (phone_t *) IPC_GET_ARG5(*olddata); 229 230 if (IPC_GET_RETVAL(answer->data) != EOK) { 231 /* 232 * The other party on the cloned phoned rejected our 233 * request for connection on the protocol level. 234 * We need to break the connection without sending 235 * IPC_M_HUNGUP back. 236 */ 237 mutex_lock(&phone->lock); 238 if (phone->state == IPC_PHONE_CONNECTED) { 239 irq_spinlock_lock(&phone->callee->lock, true); 240 list_remove(&phone->link); 241 phone->state = IPC_PHONE_SLAMMED; 242 irq_spinlock_unlock(&phone->callee->lock, true); 243 } 244 mutex_unlock(&phone->lock); 245 } 246 } else if (IPC_GET_IMETHOD(*olddata) == IPC_M_CONNECT_TO_ME) { 247 int phoneid = IPC_GET_ARG5(*olddata); 248 249 if (IPC_GET_RETVAL(answer->data) != EOK) { 250 /* The connection was not accepted */ 251 phone_dealloc(phoneid); 252 } else { 253 /* The connection was accepted */ 254 phone_connect(phoneid, &answer->sender->answerbox); 255 /* Set 'phone hash' as arg5 of response */ 256 IPC_SET_ARG5(answer->data, 257 (sysarg_t) &TASK->phones[phoneid]); 258 } 259 } else if (IPC_GET_IMETHOD(*olddata) == IPC_M_CONNECT_ME_TO) { 260 /* If the users accepted call, connect */ 261 if (IPC_GET_RETVAL(answer->data) == EOK) { 262 ipc_phone_connect((phone_t *) IPC_GET_ARG5(*olddata), 263 &TASK->answerbox); 264 } 265 } else if (IPC_GET_IMETHOD(*olddata) == IPC_M_SHARE_OUT) { 266 if (!IPC_GET_RETVAL(answer->data)) { 267 /* Accepted, handle as_area receipt */ 268 269 irq_spinlock_lock(&answer->sender->lock, true); 270 as_t *as = answer->sender->as; 271 irq_spinlock_unlock(&answer->sender->lock, true); 272 273 uintptr_t dst_base = (uintptr_t) -1; 274 int rc = as_area_share(as, IPC_GET_ARG1(*olddata), 275 IPC_GET_ARG2(*olddata), AS, IPC_GET_ARG3(*olddata), 276 &dst_base, IPC_GET_ARG1(answer->data)); 277 278 if (rc == EOK) 279 rc = copy_to_uspace((void *) IPC_GET_ARG2(answer->data), 280 &dst_base, sizeof(dst_base)); 281 282 IPC_SET_RETVAL(answer->data, rc); 283 return rc; 284 } 285 } else if (IPC_GET_IMETHOD(*olddata) == IPC_M_SHARE_IN) { 286 if (!IPC_GET_RETVAL(answer->data)) { 287 irq_spinlock_lock(&answer->sender->lock, true); 288 as_t *as = answer->sender->as; 289 irq_spinlock_unlock(&answer->sender->lock, true); 290 291 uintptr_t dst_base = (uintptr_t) -1; 292 int rc = as_area_share(AS, IPC_GET_ARG1(answer->data), 293 IPC_GET_ARG1(*olddata), as, IPC_GET_ARG2(answer->data), 294 &dst_base, IPC_GET_ARG3(answer->data)); 295 IPC_SET_ARG4(answer->data, dst_base); 296 IPC_SET_RETVAL(answer->data, rc); 297 } 298 } else if (IPC_GET_IMETHOD(*olddata) == IPC_M_DATA_READ) { 299 ASSERT(!answer->buffer); 300 if (!IPC_GET_RETVAL(answer->data)) { 301 /* The recipient agreed to send data. */ 302 uintptr_t src = IPC_GET_ARG1(answer->data); 303 uintptr_t dst = IPC_GET_ARG1(*olddata); 304 size_t max_size = IPC_GET_ARG2(*olddata); 305 size_t size = IPC_GET_ARG2(answer->data); 306 if (size && size <= max_size) { 307 /* 308 * Copy the destination VA so that this piece of 309 * information is not lost. 310 */ 311 IPC_SET_ARG1(answer->data, dst); 312 313 answer->buffer = malloc(size, 0); 314 int rc = copy_from_uspace(answer->buffer, 315 (void *) src, size); 316 if (rc) { 317 IPC_SET_RETVAL(answer->data, rc); 318 free(answer->buffer); 319 answer->buffer = NULL; 320 } 321 } else if (!size) { 322 IPC_SET_RETVAL(answer->data, EOK); 323 } else { 324 IPC_SET_RETVAL(answer->data, ELIMIT); 325 } 326 } 327 } else if (IPC_GET_IMETHOD(*olddata) == IPC_M_DATA_WRITE) { 328 ASSERT(answer->buffer); 329 if (!IPC_GET_RETVAL(answer->data)) { 330 /* The recipient agreed to receive data. */ 331 uintptr_t dst = (uintptr_t)IPC_GET_ARG1(answer->data); 332 size_t size = (size_t)IPC_GET_ARG2(answer->data); 333 size_t max_size = (size_t)IPC_GET_ARG2(*olddata); 334 335 if (size <= max_size) { 336 int rc = copy_to_uspace((void *) dst, 337 answer->buffer, size); 338 if (rc) 339 IPC_SET_RETVAL(answer->data, rc); 340 } else { 341 IPC_SET_RETVAL(answer->data, ELIMIT); 342 } 343 } 344 free(answer->buffer); 345 answer->buffer = NULL; 346 } else if (IPC_GET_IMETHOD(*olddata) == IPC_M_STATE_CHANGE_AUTHORIZE) { 347 if (!IPC_GET_RETVAL(answer->data)) { 348 /* The recipient authorized the change of state. */ 349 phone_t *recipient_phone; 350 task_t *other_task_s; 351 task_t *other_task_r; 352 int rc; 353 354 rc = phone_get(IPC_GET_ARG1(answer->data), 355 &recipient_phone); 356 if (rc != EOK) { 357 IPC_SET_RETVAL(answer->data, ENOENT); 358 return ENOENT; 359 } 360 361 mutex_lock(&recipient_phone->lock); 362 if (recipient_phone->state != IPC_PHONE_CONNECTED) { 363 mutex_unlock(&recipient_phone->lock); 364 IPC_SET_RETVAL(answer->data, EINVAL); 365 return EINVAL; 366 } 367 368 other_task_r = recipient_phone->callee->task; 369 other_task_s = (task_t *) IPC_GET_ARG5(*olddata); 370 371 /* 372 * See if both the sender and the recipient meant the 373 * same third party task. 374 */ 375 if (other_task_r != other_task_s) { 376 IPC_SET_RETVAL(answer->data, EINVAL); 377 rc = EINVAL; 378 } else { 379 rc = event_task_notify_5(other_task_r, 380 EVENT_TASK_STATE_CHANGE, false, 381 IPC_GET_ARG1(*olddata), 382 IPC_GET_ARG2(*olddata), 383 IPC_GET_ARG3(*olddata), 384 LOWER32(olddata->task_id), 385 UPPER32(olddata->task_id)); 386 IPC_SET_RETVAL(answer->data, rc); 387 } 388 389 mutex_unlock(&recipient_phone->lock); 390 return rc; 391 } 392 } 393 394 return 0; 395 } 396 397 static void phones_lock(phone_t *p1, phone_t *p2) 398 { 399 if (p1 < p2) { 400 mutex_lock(&p1->lock); 401 mutex_lock(&p2->lock); 402 } else if (p1 > p2) { 403 mutex_lock(&p2->lock); 404 mutex_lock(&p1->lock); 405 } else 406 mutex_lock(&p1->lock); 407 } 408 409 static void phones_unlock(phone_t *p1, phone_t *p2) 410 { 411 mutex_unlock(&p1->lock); 412 if (p1 != p2) 413 mutex_unlock(&p2->lock); 209 return rc; 210 211 return SYSIPC_OP(answer_preprocess, answer, olddata); 414 212 } 415 213 … … 424 222 static int request_preprocess(call_t *call, phone_t *phone) 425 223 { 426 switch (IPC_GET_IMETHOD(call->data)) { 427 case IPC_M_CONNECTION_CLONE: { 428 phone_t *cloned_phone; 429 if (phone_get(IPC_GET_ARG1(call->data), &cloned_phone) != EOK) 430 return ENOENT; 431 432 phones_lock(cloned_phone, phone); 433 434 if ((cloned_phone->state != IPC_PHONE_CONNECTED) || 435 phone->state != IPC_PHONE_CONNECTED) { 436 phones_unlock(cloned_phone, phone); 437 return EINVAL; 438 } 439 440 /* 441 * We can be pretty sure now that both tasks exist and we are 442 * connected to them. As we continue to hold the phone locks, 443 * we are effectively preventing them from finishing their 444 * potential cleanup. 445 * 446 */ 447 int newphid = phone_alloc(phone->callee->task); 448 if (newphid < 0) { 449 phones_unlock(cloned_phone, phone); 450 return ELIMIT; 451 } 452 453 ipc_phone_connect(&phone->callee->task->phones[newphid], 454 cloned_phone->callee); 455 phones_unlock(cloned_phone, phone); 456 457 /* Set the new phone for the callee. */ 458 IPC_SET_ARG1(call->data, newphid); 459 break; 460 } 461 case IPC_M_CLONE_ESTABLISH: 462 IPC_SET_ARG5(call->data, (sysarg_t) phone); 463 break; 464 case IPC_M_CONNECT_ME_TO: { 465 int newphid = phone_alloc(TASK); 466 if (newphid < 0) 467 return ELIMIT; 468 469 /* Set arg5 for server */ 470 IPC_SET_ARG5(call->data, (sysarg_t) &TASK->phones[newphid]); 471 call->flags |= IPC_CALL_CONN_ME_TO; 472 call->priv = newphid; 473 break; 474 } 475 case IPC_M_SHARE_OUT: { 476 size_t size = as_area_get_size(IPC_GET_ARG1(call->data)); 477 if (!size) 478 return EPERM; 479 480 IPC_SET_ARG2(call->data, size); 481 break; 482 } 483 case IPC_M_DATA_READ: { 484 size_t size = IPC_GET_ARG2(call->data); 485 if (size > DATA_XFER_LIMIT) { 486 int flags = IPC_GET_ARG3(call->data); 487 if (flags & IPC_XF_RESTRICT) 488 IPC_SET_ARG2(call->data, DATA_XFER_LIMIT); 489 else 490 return ELIMIT; 491 } 492 break; 493 } 494 case IPC_M_DATA_WRITE: { 495 uintptr_t src = IPC_GET_ARG1(call->data); 496 size_t size = IPC_GET_ARG2(call->data); 497 498 if (size > DATA_XFER_LIMIT) { 499 int flags = IPC_GET_ARG3(call->data); 500 if (flags & IPC_XF_RESTRICT) { 501 size = DATA_XFER_LIMIT; 502 IPC_SET_ARG2(call->data, size); 503 } else 504 return ELIMIT; 505 } 506 507 call->buffer = (uint8_t *) malloc(size, 0); 508 int rc = copy_from_uspace(call->buffer, (void *) src, size); 509 if (rc != 0) { 510 free(call->buffer); 511 return rc; 512 } 513 514 break; 515 } 516 case IPC_M_STATE_CHANGE_AUTHORIZE: { 517 phone_t *sender_phone; 518 task_t *other_task_s; 519 520 if (phone_get(IPC_GET_ARG5(call->data), &sender_phone) != EOK) 521 return ENOENT; 522 523 mutex_lock(&sender_phone->lock); 524 if (sender_phone->state != IPC_PHONE_CONNECTED) { 525 mutex_unlock(&sender_phone->lock); 526 return EINVAL; 527 } 528 529 other_task_s = sender_phone->callee->task; 530 531 mutex_unlock(&sender_phone->lock); 532 533 /* Remember the third party task hash. */ 534 IPC_SET_ARG5(call->data, (sysarg_t) other_task_s); 535 break; 536 } 537 #ifdef CONFIG_UDEBUG 538 case IPC_M_DEBUG: 539 return udebug_request_preprocess(call, phone); 540 #endif 541 default: 542 break; 543 } 544 545 return 0; 224 call->request_method = IPC_GET_IMETHOD(call->data); 225 return SYSIPC_OP(request_preprocess, call, phone); 546 226 } 547 227 … … 561 241 IPC_SET_RETVAL(call->data, EFORWARD); 562 242 563 if (call->flags & IPC_CALL_CONN_ME_TO) { 564 if (IPC_GET_RETVAL(call->data)) 565 phone_dealloc(call->priv); 566 else 567 IPC_SET_ARG5(call->data, call->priv); 568 } 569 570 if (call->buffer) { 571 /* 572 * This must be an affirmative answer to IPC_M_DATA_READ 573 * or IPC_M_DEBUG/UDEBUG_M_MEM_READ... 574 * 575 */ 576 uintptr_t dst = IPC_GET_ARG1(call->data); 577 size_t size = IPC_GET_ARG2(call->data); 578 int rc = copy_to_uspace((void *) dst, call->buffer, size); 579 if (rc) 580 IPC_SET_RETVAL(call->data, rc); 581 free(call->buffer); 582 call->buffer = NULL; 583 } 584 } 243 SYSIPC_OP(answer_process, call); 244 } 245 585 246 586 247 /** Do basic kernel processing of received call request. … … 595 256 static int process_request(answerbox_t *box, call_t *call) 596 257 { 597 if (IPC_GET_IMETHOD(call->data) == IPC_M_CONNECT_TO_ME) { 598 int phoneid = phone_alloc(TASK); 599 if (phoneid < 0) { /* Failed to allocate phone */ 600 IPC_SET_RETVAL(call->data, ELIMIT); 601 ipc_answer(box, call); 602 return -1; 603 } 604 605 IPC_SET_ARG5(call->data, phoneid); 606 } 607 608 switch (IPC_GET_IMETHOD(call->data)) { 609 case IPC_M_DEBUG: 610 return -1; 611 default: 612 break; 613 } 614 615 return 0; 258 return SYSIPC_OP(request_process, call, box); 616 259 } 617 260 … … 745 388 { 746 389 call_t *call = get_call(callid); 390 phone_t *phone; 391 bool need_old = answer_need_old(call); 392 bool after_forward = false; 393 ipc_data_t old; 394 int rc; 395 747 396 if (!call) 748 397 return ENOENT; 749 398 399 if (need_old) 400 old = call->data; 401 402 if (phone_get(phoneid, &phone) != EOK) { 403 rc = ENOENT; 404 goto error; 405 } 406 407 if (!method_is_forwardable(IPC_GET_IMETHOD(call->data))) { 408 rc = EPERM; 409 goto error; 410 } 411 750 412 call->flags |= IPC_CALL_FORWARDED; 751 752 phone_t *phone;753 if (phone_get(phoneid, &phone) != EOK) {754 IPC_SET_RETVAL(call->data, EFORWARD);755 ipc_answer(&TASK->answerbox, call);756 return ENOENT;757 }758 759 if (!method_is_forwardable(IPC_GET_IMETHOD(call->data))) {760 IPC_SET_RETVAL(call->data, EFORWARD);761 ipc_answer(&TASK->answerbox, call);762 return EPERM;763 }764 413 765 414 /* … … 797 446 } 798 447 799 return ipc_forward(call, phone, &TASK->answerbox, mode); 448 rc = ipc_forward(call, phone, &TASK->answerbox, mode); 449 if (rc != EOK) { 450 after_forward = true; 451 goto error; 452 } 453 454 return EOK; 455 456 error: 457 IPC_SET_RETVAL(call->data, EFORWARD); 458 (void) answer_preprocess(call, need_old ? &old : NULL); 459 if (after_forward) 460 _ipc_answer_free_call(call, false); 461 else 462 ipc_answer(&TASK->answerbox, call); 463 464 return rc; 800 465 } 801 466 -
kernel/generic/src/main/kinit.c
r7eb49f4 re2a6b72 69 69 #include <str.h> 70 70 #include <sysinfo/stats.h> 71 #include <sysinfo/sysinfo.h> 71 72 #include <align.h> 72 73 … … 179 180 program_t programs[CONFIG_INIT_TASKS]; 180 181 182 // FIXME: do not propagate arguments through sysinfo 183 // but pass them directly to the tasks 184 for (i = 0; i < init.cnt; i++) { 185 const char *arguments = init.tasks[i].arguments; 186 if (str_length(arguments) == 0) 187 continue; 188 if (str_length(init.tasks[i].name) == 0) 189 continue; 190 size_t arguments_size = str_size(arguments); 191 192 void *arguments_copy = malloc(arguments_size, 0); 193 if (arguments_copy == NULL) 194 continue; 195 memcpy(arguments_copy, arguments, arguments_size); 196 197 char item_name[CONFIG_TASK_NAME_BUFLEN + 15]; 198 snprintf(item_name, CONFIG_TASK_NAME_BUFLEN + 15, 199 "init_args.%s", init.tasks[i].name); 200 201 sysinfo_set_item_data(item_name, NULL, arguments_copy, arguments_size); 202 } 203 181 204 for (i = 0; i < init.cnt; i++) { 182 205 if (init.tasks[i].paddr % FRAME_SIZE) { -
kernel/generic/src/mm/as.c
r7eb49f4 re2a6b72 2054 2054 { 2055 2055 uintptr_t virt = base; 2056 as_area_t *area = as_area_create(AS, flags | AS_AREA_CACHEABLE, size,2056 as_area_t *area = as_area_create(AS, flags, size, 2057 2057 AS_AREA_ATTR_NONE, &anon_backend, NULL, &virt, bound); 2058 2058 if (area == NULL) -
kernel/generic/src/proc/task.c
r7eb49f4 re2a6b72 161 161 size_t i; 162 162 for (i = 0; i < IPC_MAX_PHONES; i++) 163 ipc_phone_init(&task->phones[i]); 163 ipc_phone_init(&task->phones[i], task); 164 165 spinlock_initialize(&task->active_calls_lock, "active_calls_lock"); 166 list_initialize(&task->active_calls); 164 167 165 168 #ifdef CONFIG_UDEBUG … … 203 206 event_task_init(task); 204 207 208 task->answerbox.active = true; 209 205 210 #ifdef CONFIG_UDEBUG 206 211 /* Init debugging stuff */ … … 208 213 209 214 /* Init kbox stuff */ 215 task->kb.box.active = true; 210 216 task->kb.finished = false; 211 217 #endif … … 213 219 if ((ipc_phone_0) && 214 220 (container_check(ipc_phone_0->task->container, task->container))) 215 ipc_phone_connect(&task->phones[0], ipc_phone_0);221 (void) ipc_phone_connect(&task->phones[0], ipc_phone_0); 216 222 217 223 btree_create(&task->futexes);
Note:
See TracChangeset
for help on using the changeset viewer.