Changeset 8b243f2 in mainline
- Timestamp:
- 2007-06-17T19:34:36Z (18 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- bd72c3e9
- Parents:
- 4680ef5
- Files:
-
- 12 edited
Legend:
- Unmodified
- Added
- Removed
-
kernel/generic/include/ipc/ipc.h
r4680ef5 r8b243f2 38 38 /* Length of data being transfered with IPC call */ 39 39 /* - the uspace may not be able to utilize full length */ 40 #define IPC_CALL_LEN 40 #define IPC_CALL_LEN 4 41 41 42 42 /** Maximum active async calls per thread */ 43 43 #ifdef CONFIG_DEBUG 44 # define IPC_MAX_ASYNC_CALLS444 #define IPC_MAX_ASYNC_CALLS 4 45 45 #else 46 # define IPC_MAX_ASYNC_CALLS400046 #define IPC_MAX_ASYNC_CALLS 4000 47 47 #endif 48 48 … … 62 62 #define IPC_CALL_NOTIF (1 << 5) 63 63 64 /* Flags of callid (the addresses are aligned at least to 4, 65 * that is why we can use bottom 2 bits of the call address 66 */ 67 /** Type of this msg is 'answer' */ 64 /* 65 * Bits used in call hashes. 66 * The addresses are aligned at least to 4 that is why we can use the 2 least 67 * significant bits of the call address. 68 */ 69 /** Type of this call is 'answer' */ 68 70 #define IPC_CALLID_ANSWERED 1 69 /** Type of this msgis 'notification' */71 /** Type of this call is 'notification' */ 70 72 #define IPC_CALLID_NOTIFICATION 2 71 73 72 /* Return values from IPC_ASYNC*/74 /* Return values from sys_ipc_call_async(). */ 73 75 #define IPC_CALLRET_FATAL -1 74 76 #define IPC_CALLRET_TEMPORARY -2 … … 112 114 * - the caller obtains taskid of the called thread 113 115 */ 114 #define IPC_M_CONNECT_TO_ME 116 #define IPC_M_CONNECT_TO_ME 1 115 117 /** Protocol for CONNECT - ME - TO 116 118 * … … 131 133 * 132 134 */ 133 #define IPC_M_CONNECT_ME_TO 135 #define IPC_M_CONNECT_ME_TO 2 134 136 /** This message is sent to answerbox when the phone 135 137 * is hung up 136 138 */ 137 #define IPC_M_PHONE_HUNGUP 139 #define IPC_M_PHONE_HUNGUP 3 138 140 139 141 /** Send as_area over IPC … … 145 147 * - ARG1 - dst as_area base adress 146 148 */ 147 #define IPC_M_AS_AREA_SEND 149 #define IPC_M_AS_AREA_SEND 5 148 150 149 151 /** Get as_area over IPC … … 157 159 * - ARG2 - flags that will be used for sharing 158 160 */ 159 #define IPC_M_AS_AREA_RECV 161 #define IPC_M_AS_AREA_RECV 6 160 162 161 163 162 164 /* Well-known methods */ 163 #define IPC_M_LAST_SYSTEM 164 #define IPC_M_PING 165 #define IPC_M_LAST_SYSTEM 511 166 #define IPC_M_PING 512 165 167 /* User methods */ 166 #define FIRST_USER_METHOD 168 #define FIRST_USER_METHOD 1024 167 169 168 170 #ifdef KERNEL … … 204 206 waitq_t wq; 205 207 206 /** Phones connected to this answerbox */208 /** Phones connected to this answerbox. */ 207 209 link_t connected_phones; 208 /** Received calls */210 /** Received calls. */ 209 211 link_t calls; 210 212 link_t dispatched_calls; /* Should be hash table in the future */ 211 213 212 /** Answered calls */214 /** Answered calls. */ 213 215 link_t answers; 214 216 215 217 SPINLOCK_DECLARE(irq_lock); 216 /** Notifications from IRQ handlers */218 /** Notifications from IRQ handlers. */ 217 219 link_t irq_notifs; 218 220 /** IRQs with notifications to this answerbox. */ … … 230 232 int flags; 231 233 232 /* Identification of the caller*/234 /** Identification of the caller. */ 233 235 struct task *sender; 234 /* The caller box is different from sender->answerbox 235 * for synchronous calls 236 */ 236 /** The caller box is different from sender->answerbox for synchronous 237 * calls. */ 237 238 answerbox_t *callerbox; 238 239 239 /** Private data to internal IPC */240 /** Private data to internal IPC. */ 240 241 unative_t priv; 241 242 242 /** Data passed from/to userspace */243 /** Data passed from/to userspace. */ 243 244 ipc_data_t data; 244 245 } call_t; -
kernel/generic/include/ipc/ipcrsc.h
r4680ef5 r8b243f2 36 36 #define KERN_IPCRSC_H_ 37 37 38 call_t * get_call(unative_t callid);39 int phone_alloc(void);40 void phone_connect(int phoneid, answerbox_t *box);41 void phone_dealloc(int phoneid);38 extern call_t * get_call(unative_t callid); 39 extern int phone_alloc(void); 40 extern void phone_connect(int phoneid, answerbox_t *box); 41 extern void phone_dealloc(int phoneid); 42 42 43 43 #endif -
kernel/generic/include/ipc/irq.h
r4680ef5 r8b243f2 37 37 38 38 /** Maximum length of IPC IRQ program */ 39 #define IRQ_MAX_PROG_SIZE 39 #define IRQ_MAX_PROG_SIZE 10 40 40 41 41 #include <ipc/ipc.h> … … 47 47 unative_t method, irq_code_t *ucode); 48 48 extern void ipc_irq_send_notif(irq_t *irq); 49 extern void ipc_irq_send_msg(irq_t *irq, unative_t a1, unative_t a2, unative_t a3); 49 extern void ipc_irq_send_msg(irq_t *irq, unative_t a1, unative_t a2, 50 unative_t a3); 50 51 extern void ipc_irq_unregister(answerbox_t *box, inr_t inr, devno_t devno); 51 52 extern void ipc_irq_cleanup(answerbox_t *box); -
kernel/generic/src/ipc/ipc.c
r4680ef5 r8b243f2 35 35 /* Lock ordering 36 36 * 37 * First the answerbox, then the phone 37 * First the answerbox, then the phone. 38 38 */ 39 39 … … 54 54 #include <ipc/irq.h> 55 55 56 /* Open channel that is assigned automatically to new tasks */56 /** Open channel that is assigned automatically to new tasks */ 57 57 answerbox_t *ipc_phone_0 = NULL; 58 58 59 59 static slab_cache_t *ipc_call_slab; 60 60 61 /* Initialize new call */ 61 /** Initialize a call structure. 62 * 63 * @param call Call structure to be initialized. 64 */ 62 65 static void _ipc_call_init(call_t *call) 63 66 { 64 memsetb((uintptr_t) call, sizeof(*call), 0);67 memsetb((uintptr_t) call, sizeof(*call), 0); 65 68 call->callerbox = &TASK->answerbox; 66 69 call->sender = TASK; 67 70 } 68 71 69 /** Allocate & initialize call structure72 /** Allocate and initialize a call structure. 70 73 * 71 * The call is initialized, so that the reply will be directed 72 * to TASK->answerbox 73 * 74 * @param flags Parameters for slab_alloc (ATOMIC, etc.) 75 */ 76 call_t * ipc_call_alloc(int flags) 74 * The call is initialized, so that the reply will be directed to 75 * TASK->answerbox. 76 * 77 * @param flags Parameters for slab_alloc (e.g FRAME_ATOMIC). 78 * 79 * @return If flags permit it, return NULL, or initialized kernel 80 * call structure. 81 */ 82 call_t *ipc_call_alloc(int flags) 77 83 { 78 84 call_t *call; … … 84 90 } 85 91 86 /** Initialize allocated call */ 92 /** Initialize a statically allocated call structure. 93 * 94 * @param call Statically allocated kernel call structure to be 95 * initialized. 96 */ 87 97 void ipc_call_static_init(call_t *call) 88 98 { … … 91 101 } 92 102 93 /** Deallocate call stracuture */ 103 /** Deallocate a call stracuture. 104 * 105 * @param call Call structure to be freed. 106 */ 94 107 void ipc_call_free(call_t *call) 95 108 { 109 ASSERT(!(call->flags & IPC_CALL_STATIC_ALLOC)); 96 110 slab_free(ipc_call_slab, call); 97 111 } 98 112 99 /** Initialize answerbox structure 113 /** Initialize an answerbox structure. 114 * 115 * @param box Answerbox structure to be initialized. 100 116 */ 101 117 void ipc_answerbox_init(answerbox_t *box) … … 113 129 } 114 130 115 /** Connect phone to answerbox */ 131 /** Connect a phone to an answerbox. 132 * 133 * @param phone Initialized phone structure. 134 * @param box Initialized answerbox structure. 135 */ 116 136 void ipc_phone_connect(phone_t *phone, answerbox_t *box) 117 137 { … … 128 148 } 129 149 130 /** Initialize phone structure and connect phone to answerbox 150 /** Initialize a phone structure. 151 * 152 * @param phone Phone structure to be initialized. 131 153 */ 132 154 void ipc_phone_init(phone_t *phone) … … 138 160 } 139 161 140 /** Helper function to facilitate synchronous calls */ 162 /** Helper function to facilitate synchronous calls. 163 * 164 * @param phone Destination kernel phone structure. 165 * @param request Call structure with request. 166 */ 141 167 void ipc_call_sync(phone_t *phone, call_t *request) 142 168 { … … 145 171 ipc_answerbox_init(&sync_box); 146 172 147 /* We will receive data on special box*/173 /* We will receive data in a special box. */ 148 174 request->callerbox = &sync_box; 149 175 … … 152 178 } 153 179 154 /** Answer message that was not dispatched and is not entered in 155 * any queue 180 /** Answer a message which was not dispatched and is not listed in any queue. 181 * 182 * @param call Call structure to be answered. 156 183 */ 157 184 static void _ipc_answer_free_call(call_t *call) … … 167 194 } 168 195 169 /** Answer message, that is in callee queue170 * 171 * @param box Answerbox that is answering the message172 * @param call Modified request that is being sent back196 /** Answer a message which is in a callee queue. 197 * 198 * @param box Answerbox that is answering the message. 199 * @param call Modified request that is being sent back. 173 200 */ 174 201 void ipc_answer(answerbox_t *box, call_t *call) … … 182 209 } 183 210 184 /** Simulate sending back a message 211 /** Simulate sending back a message. 185 212 * 186 213 * Most errors are better handled by forming a normal backward 187 214 * message and sending it as a normal answer. 215 * 216 * @param phone Phone structure the call should appear to come from. 217 * @param call Call structure to be answered. 218 * @param err Return value to be used for the answer. 188 219 */ 189 220 void ipc_backsend_err(phone_t *phone, call_t *call, unative_t err) … … 195 226 } 196 227 197 /* Unsafe unchecking ipc_call */ 228 /** Unsafe unchecking version of ipc_call. 229 * 230 * @param phone Phone structure the call comes from. 231 * @param box Destination answerbox structure. 232 */ 198 233 static void _ipc_call(phone_t *phone, answerbox_t *box, call_t *call) 199 234 { 200 if (! 235 if (!(call->flags & IPC_CALL_FORWARDED)) { 201 236 atomic_inc(&phone->active_calls); 202 237 call->data.phone = phone; … … 209 244 } 210 245 211 /** Send a asynchronous request using phone to answerbox 212 * 213 * @param phone Phone connected to answerbox. 214 * @param call Structure representing the call. 246 /** Send an asynchronous request using a phone to an answerbox. 247 * 248 * @param phone Phone structure the call comes from and which is 249 * connected to the destination answerbox. 250 * @param call Call structure with request. 251 * 252 * @return Return 0 on success, ENOENT on error. 215 253 */ 216 254 int ipc_call(phone_t *phone, call_t *call) … … 239 277 } 240 278 241 /** Disconnect phone from answerbox 242 * 243 * This call leaves the phone in HUNGUP state. The change to 'free' is done279 /** Disconnect phone from answerbox. 280 * 281 * This call leaves the phone in the HUNGUP state. The change to 'free' is done 244 282 * lazily later. 245 283 * 246 * @param phone Phone to be hung up284 * @param phone Phone structure to be hung up. 247 285 * 248 * @return 0 - phone disconnected, -1 - the phone was already disconnected 286 * @return Return 0 if the phone is disconnected. 287 * Return -1 if the phone was already disconnected. 249 288 */ 250 289 int ipc_phone_hangup(phone_t *phone) … … 254 293 255 294 spinlock_lock(&phone->lock); 256 if (phone->state == IPC_PHONE_FREE || phone->state == IPC_PHONE_HUNGUP \257 ||phone->state == IPC_PHONE_CONNECTING) {295 if (phone->state == IPC_PHONE_FREE || phone->state == IPC_PHONE_HUNGUP || 296 phone->state == IPC_PHONE_CONNECTING) { 258 297 spinlock_unlock(&phone->lock); 259 298 return -1; … … 280 319 } 281 320 282 /** Forwards call from one answerbox to a new one 283 * 284 * @param call Call to be redirected. 285 * @param newphone Phone to target answerbox. 286 * @param oldbox Old answerbox 287 * @return 0 on forward ok, error code, if there was error 321 /** Forwards call from one answerbox to another one. 322 * 323 * @param call Call structure to be redirected. 324 * @param newphone Phone structure to target answerbox. 325 * @param oldbox Old answerbox structure. 326 * 327 * @return Return 0 if forwarding succeeded or an error code if 328 * there was error. 288 329 * 289 * - the return value serves only as an information for the forwarder,290 * the original caller is notified automatically with EFORWARD330 * The return value serves only as an information for the forwarder, 331 * the original caller is notified automatically with EFORWARD. 291 332 */ 292 333 int ipc_forward(call_t *call, phone_t *newphone, answerbox_t *oldbox) … … 300 341 301 342 302 /** Wait for phone call 303 * 304 * @param box Answerbox expecting the call. 305 * @param usec Timeout in microseconds. See documentation for waitq_sleep_timeout() for 306 * decription of its special meaning. 307 * @param flags Select mode of sleep operation. See documentation for waitq_sleep_timeout()i 308 * for description of its special meaning. 309 * @return Recived message address 310 * - to distinguish between call and answer, look at call->flags 311 */ 312 call_t * ipc_wait_for_call(answerbox_t *box, uint32_t usec, int flags) 343 /** Wait for a phone call. 344 * 345 * @param box Answerbox expecting the call. 346 * @param usec Timeout in microseconds. See documentation for 347 * waitq_sleep_timeout() for decription of its special 348 * meaning. 349 * @param flags Select mode of sleep operation. See documentation for 350 * waitq_sleep_timeout() for description of its special 351 * meaning. 352 * @return Recived call structure or NULL. 353 * 354 * To distinguish between a call and an answer, have a look at call->flags. 355 */ 356 call_t *ipc_wait_for_call(answerbox_t *box, uint32_t usec, int flags) 313 357 { 314 358 call_t *request; … … 351 395 } 352 396 353 /** Answer all calls from list with EHANGUP msg */ 397 /** Answer all calls from list with EHANGUP answer. 398 * 399 * @param lst Head of the list to be cleaned up. 400 */ 354 401 static void ipc_cleanup_call_list(link_t *lst) 355 402 { … … 365 412 } 366 413 367 /** Cleans up all IPC communication of the current task 414 /** Cleans up all IPC communication of the current task. 368 415 * 369 416 * Note: ipc_hangup sets returning answerbox to TASK->answerbox, you 370 * have to change it as well if you want to cleanup other current then current.417 * have to change it as well if you want to cleanup other tasks than TASK. 371 418 */ 372 419 void ipc_cleanup(void) … … 378 425 379 426 /* Disconnect all our phones ('ipc_phone_hangup') */ 380 for (i =0;i < IPC_MAX_PHONES; i++)427 for (i = 0; i < IPC_MAX_PHONES; i++) 381 428 ipc_phone_hangup(&TASK->phones[i]); 382 429 … … 414 461 /* Locking not needed, no one else should modify 415 462 * it, when we are in cleanup */ 416 for (i =0;i < IPC_MAX_PHONES; i++) {417 if (TASK->phones[i].state == IPC_PHONE_HUNGUP && \463 for (i = 0; i < IPC_MAX_PHONES; i++) { 464 if (TASK->phones[i].state == IPC_PHONE_HUNGUP && 418 465 atomic_get(&TASK->phones[i].active_calls) == 0) 419 466 TASK->phones[i].state = IPC_PHONE_FREE; … … 434 481 break; 435 482 436 call = ipc_wait_for_call(&TASK->answerbox, SYNCH_NO_TIMEOUT, SYNCH_FLAGS_NONE); 437 ASSERT((call->flags & IPC_CALL_ANSWERED) || (call->flags & IPC_CALL_NOTIF)); 438 ASSERT(! (call->flags & IPC_CALL_STATIC_ALLOC)); 483 call = ipc_wait_for_call(&TASK->answerbox, SYNCH_NO_TIMEOUT, 484 SYNCH_FLAGS_NONE); 485 ASSERT((call->flags & IPC_CALL_ANSWERED) || 486 (call->flags & IPC_CALL_NOTIF)); 487 ASSERT(!(call->flags & IPC_CALL_STATIC_ALLOC)); 439 488 440 489 atomic_dec(&TASK->active_calls); … … 447 496 void ipc_init(void) 448 497 { 449 ipc_call_slab = slab_cache_create("ipc_call", sizeof(call_t), 0, NULL, NULL, 0); 450 } 451 452 453 /** Kconsole - list answerbox contents */ 498 ipc_call_slab = slab_cache_create("ipc_call", sizeof(call_t), 0, NULL, 499 NULL, 0); 500 } 501 502 503 /** List answerbox contents. 504 * 505 * @param taskid Task ID. 506 */ 454 507 void ipc_print_task(task_id_t taskid) 455 508 { … … 469 522 /* Print opened phones & details */ 470 523 printf("PHONE:\n"); 471 for (i =0; i < IPC_MAX_PHONES;i++) {524 for (i = 0; i < IPC_MAX_PHONES; i++) { 472 525 spinlock_lock(&task->phones[i].lock); 473 526 if (task->phones[i].state != IPC_PHONE_FREE) { 474 printf("%d: ", i);527 printf("%d: ", i); 475 528 switch (task->phones[i].state) { 476 529 case IPC_PHONE_CONNECTING: -
kernel/generic/src/ipc/ipcrsc.c
r4680ef5 r8b243f2 133 133 #include <debug.h> 134 134 135 /** Find call_t * in call table according to callid 136 * 137 * TODO: Some speedup (hash table?) 138 * @return NULL on not found, otherwise pointer to call structure 139 */ 140 call_t * get_call(unative_t callid) 135 /** Find call_t * in call table according to callid. 136 * 137 * @todo Some speedup (hash table?) 138 * 139 * @param callid Userspace hash of the call. Currently it is the call 140 * structure kernel address. 141 * 142 * @return NULL on not found, otherwise pointer to the call 143 * structure. 144 */ 145 call_t *get_call(unative_t callid) 141 146 { 142 147 link_t *lst; … … 145 150 spinlock_lock(&TASK->answerbox.lock); 146 151 for (lst = TASK->answerbox.dispatched_calls.next; 147 152 lst != &TASK->answerbox.dispatched_calls; lst = lst->next) { 148 153 call = list_get_instance(lst, call_t, link); 149 if ((unative_t) call == callid) {154 if ((unative_t) call == callid) { 150 155 result = call; 151 156 break; … … 156 161 } 157 162 158 /** Allocate new phone slot in current TASK structure */ 163 /** Allocate new phone slot in the current TASK structure. 164 * 165 * @return New phone handle or -1 if the phone handle limit is 166 * exceeded. 167 */ 159 168 int phone_alloc(void) 160 169 { … … 163 172 spinlock_lock(&TASK->lock); 164 173 165 for (i =0; i < IPC_MAX_PHONES; i++) {166 if (TASK->phones[i].state == IPC_PHONE_HUNGUP && \174 for (i = 0; i < IPC_MAX_PHONES; i++) { 175 if (TASK->phones[i].state == IPC_PHONE_HUNGUP && 167 176 atomic_get(&TASK->phones[i].active_calls) == 0) 168 177 TASK->phones[i].state = IPC_PHONE_FREE; … … 180 189 } 181 190 191 /** Mark a phone structure free. 192 * 193 * @param phone Phone structure to be marked free. 194 */ 182 195 static void phone_deallocp(phone_t *phone) 183 196 { … … 188 201 } 189 202 190 /** Free slot from a disconnected phone 191 * 192 * All already sent messages will be correctly processed 203 /** Free slot from a disconnected phone. 204 * 205 * All already sent messages will be correctly processed. 206 * 207 * @param phoneid Phone handle of the phone to be freed. 193 208 */ 194 209 void phone_dealloc(int phoneid) … … 197 212 } 198 213 199 /** Connect phone to a given answerbox 200 * 201 * @param phoneid The slot that will be connected 214 /** Connect phone to a given answerbox. 215 * 216 * @param phoneid Phone handle to be connected. 217 * @param box Answerbox to which to connect the phone handle. 202 218 * 203 219 * The procedure _enforces_ that the user first marks the phone -
kernel/generic/src/ipc/irq.c
r4680ef5 r8b243f2 61 61 /** Execute code associated with IRQ notification. 62 62 * 63 * @param call 64 * @param code 63 * @param call Notification call. 64 * @param code Top-half pseudocode. 65 65 */ 66 66 static void code_execute(call_t *call, irq_code_t *code) … … 72 72 return; 73 73 74 for (i =0; i < code->cmdcount;i++) {74 for (i = 0; i < code->cmdcount; i++) { 75 75 switch (code->cmds[i].cmd) { 76 76 case CMD_MEM_READ_1: 77 dstval = *((uint8_t *) code->cmds[i].addr);77 dstval = *((uint8_t *) code->cmds[i].addr); 78 78 break; 79 79 case CMD_MEM_READ_2: 80 dstval = *((uint16_t *) code->cmds[i].addr);80 dstval = *((uint16_t *) code->cmds[i].addr); 81 81 break; 82 82 case CMD_MEM_READ_4: 83 dstval = *((uint32_t *) code->cmds[i].addr);83 dstval = *((uint32_t *) code->cmds[i].addr); 84 84 break; 85 85 case CMD_MEM_READ_8: 86 dstval = *((uint64_t *) code->cmds[i].addr);86 dstval = *((uint64_t *) code->cmds[i].addr); 87 87 break; 88 88 case CMD_MEM_WRITE_1: 89 *((uint8_t *) code->cmds[i].addr) = code->cmds[i].value;89 *((uint8_t *) code->cmds[i].addr) = code->cmds[i].value; 90 90 break; 91 91 case CMD_MEM_WRITE_2: 92 *((uint16_t *) code->cmds[i].addr) = code->cmds[i].value;92 *((uint16_t *) code->cmds[i].addr) = code->cmds[i].value; 93 93 break; 94 94 case CMD_MEM_WRITE_4: 95 *((uint32_t *) code->cmds[i].addr) = code->cmds[i].value;95 *((uint32_t *) code->cmds[i].addr) = code->cmds[i].value; 96 96 break; 97 97 case CMD_MEM_WRITE_8: 98 *((uint64_t *) code->cmds[i].addr) = code->cmds[i].value;98 *((uint64_t *) code->cmds[i].addr) = code->cmds[i].value; 99 99 break; 100 100 #if defined(ia32) || defined(amd64) 101 101 case CMD_PORT_READ_1: 102 dstval = inb((long) code->cmds[i].addr);102 dstval = inb((long) code->cmds[i].addr); 103 103 break; 104 104 case CMD_PORT_WRITE_1: 105 outb((long) code->cmds[i].addr, code->cmds[i].value);105 outb((long) code->cmds[i].addr, code->cmds[i].value); 106 106 break; 107 107 #endif … … 125 125 } 126 126 127 /** Free top-half pseudocode. 128 * 129 * @param code Pointer to the top-half pseudocode. 130 */ 127 131 static void code_free(irq_code_t *code) 128 132 { … … 133 137 } 134 138 135 static irq_code_t * code_from_uspace(irq_code_t *ucode) 139 /** Copy top-half pseudocode from userspace into the kernel. 140 * 141 * @param ucode Userspace address of the top-half pseudocode. 142 * 143 * @return Kernel address of the copied pseudocode. 144 */ 145 static irq_code_t *code_from_uspace(irq_code_t *ucode) 136 146 { 137 147 irq_code_t *code; … … 151 161 } 152 162 ucmds = code->cmds; 153 code->cmds = malloc(sizeof(code->cmds[0]) * (code->cmdcount), 0); 154 rc = copy_from_uspace(code->cmds, ucmds, sizeof(code->cmds[0]) * (code->cmdcount)); 163 code->cmds = malloc(sizeof(code->cmds[0]) * code->cmdcount, 0); 164 rc = copy_from_uspace(code->cmds, ucmds, 165 sizeof(code->cmds[0]) * code->cmdcount); 155 166 if (rc != 0) { 156 167 free(code->cmds); … … 164 175 /** Unregister task from IRQ notification. 165 176 * 166 * @param box 167 * @param inr IRQ numbe.168 * @param devno 177 * @param box Answerbox associated with the notification. 178 * @param inr IRQ number. 179 * @param devno Device number. 169 180 */ 170 181 void ipc_irq_unregister(answerbox_t *box, inr_t inr, devno_t devno) … … 196 207 /** Register an answerbox as a receiving end for IRQ notifications. 197 208 * 198 * @param box Receiving answerbox. 199 * @param inr IRQ number. 200 * @param devno Device number. 201 * @param method Method to be associated with the notification. 202 * @param ucode Uspace pointer to top-half pseudocode. 203 * 204 * @return EBADMEM, ENOENT or EEXISTS on failure or 0 on success. 205 */ 206 int ipc_irq_register(answerbox_t *box, inr_t inr, devno_t devno, unative_t method, irq_code_t *ucode) 209 * @param box Receiving answerbox. 210 * @param inr IRQ number. 211 * @param devno Device number. 212 * @param method Method to be associated with the notification. 213 * @param ucode Uspace pointer to top-half pseudocode. 214 * 215 * @return EBADMEM, ENOENT or EEXISTS on failure or 0 on success. 216 */ 217 int ipc_irq_register(answerbox_t *box, inr_t inr, devno_t devno, 218 unative_t method, irq_code_t *ucode) 207 219 { 208 220 ipl_t ipl; … … 214 226 if (!code) 215 227 return EBADMEM; 216 } else 228 } else { 217 229 code = NULL; 230 } 218 231 219 232 ipl = interrupts_disable(); … … 248 261 } 249 262 250 /** Add call toproper answerbox queue.263 /** Add a call to the proper answerbox queue. 251 264 * 252 265 * Assume irq->lock is locked. 253 266 * 267 * @param irq IRQ structure referencing the target answerbox. 268 * @param call IRQ notification call. 254 269 */ 255 270 static void send_call(irq_t *irq, call_t *call) … … 262 277 } 263 278 264 /** Send notification message 265 * 279 /** Send notification message. 280 * 281 * @param irq IRQ structure. 282 * @param a1 Driver-specific payload argument. 283 * @param a2 Driver-specific payload argument. 284 * @param a3 Driver-specific payload argument. 266 285 */ 267 286 void ipc_irq_send_msg(irq_t *irq, unative_t a1, unative_t a2, unative_t a3) … … 290 309 } 291 310 292 /** Notify task that an irqhad occurred.311 /** Notify a task that an IRQ had occurred. 293 312 * 294 313 * We expect interrupts to be disabled and the irq->lock already held. 314 * 315 * @param irq IRQ structure. 295 316 */ 296 317 void ipc_irq_send_notif(irq_t *irq) … … 324 345 * send notifications to it. 325 346 * 326 * @param box 347 * @param box Answerbox for which we want to carry out the cleanup. 327 348 */ 328 349 void ipc_irq_cleanup(answerbox_t *box) -
kernel/generic/src/ipc/sysipc.c
r4680ef5 r8b243f2 50 50 #include <print.h> 51 51 52 #define GET_CHECK_PHONE(phone, phoneid, err) { \ 53 if (phoneid > IPC_MAX_PHONES) { err; } \ 54 phone = &TASK->phones[phoneid]; \ 55 } 56 57 #define STRUCT_TO_USPACE(dst, src) copy_to_uspace(dst, src, sizeof(*(src))) 58 59 /** Return true if the method is a system method */ 52 #define GET_CHECK_PHONE(phone, phoneid, err) \ 53 { \ 54 if (phoneid > IPC_MAX_PHONES) { \ 55 err; \ 56 } \ 57 phone = &TASK->phones[phoneid]; \ 58 } 59 60 #define STRUCT_TO_USPACE(dst, src) copy_to_uspace(dst, src, sizeof(*(src))) 61 62 /** Decide if the method is a system method. 63 * 64 * @param method Method to be decided. 65 * 66 * @return Return 1 if the method is a system method. 67 * Otherwise return 0. 68 */ 60 69 static inline int is_system_method(unative_t method) 61 70 { … … 65 74 } 66 75 67 /** Return true if the message with this method is forwardable76 /** Decide if the message with this method is forwardable. 68 77 * 69 78 * - some system messages may be forwarded, for some of them 70 79 * it is useless 80 * 81 * @param method Method to be decided. 82 * 83 * @return Return 1 if the method is forwardable. 84 * Otherwise return 0. 71 85 */ 72 86 static inline int is_forwardable(unative_t method) … … 78 92 } 79 93 80 /****************************************************/ 81 /* Functions that preprocess answer before sending 82 * it to the recepient 83 */ 84 85 /** Return true if the caller (ipc_answer) should save 86 * the old call contents for answer_preprocess 94 95 /*********************************************************************** 96 * Functions that preprocess answer before sending it to the recepient. 97 ***********************************************************************/ 98 99 /** Decide if the caller (e.g. ipc_answer()) should save the old call contents 100 * for answer_preprocess(). 101 * 102 * @param call Call structure to be decided. 103 * 104 * @return Return 1 if the old call contents should be saved. 105 * Return 0 otherwise. 87 106 */ 88 107 static inline int answer_need_old(call_t *call) … … 99 118 } 100 119 101 /** Interpret process answer as control information 102 * 103 * This function is called directly after sys_ipc_answer 120 /** Interpret process answer as control information. 121 * 122 * This function is called directly after sys_ipc_answer(). 123 * 124 * @param answer Call structure with the answer. 125 * @param olddata Saved data of the request. 126 * 127 * @return Return 0 on success or an error code. 104 128 */ 105 129 static inline int answer_preprocess(call_t *answer, ipc_data_t *olddata) … … 132 156 /* The connection was accepted */ 133 157 phone_connect(phoneid, &answer->sender->answerbox); 134 /* Set 'phone identification' as arg3 of response */158 /* Set 'phone hash' as arg3 of response */ 135 159 IPC_SET_ARG3(answer->data, 136 160 (unative_t) &TASK->phones[phoneid]); … … 182 206 } 183 207 184 /** Called before the request is sent 185 * 186 * @return 0 - no error, -1 - report error to user 208 /** Called before the request is sent. 209 * 210 * @param call Call structure with the request. 211 * 212 * @return Return 0 on success, ELIMIT or EPERM on error. 187 213 */ 188 214 static int request_preprocess(call_t *call) … … 203 229 case IPC_M_AS_AREA_SEND: 204 230 size = as_get_size(IPC_GET_ARG1(call->data)); 205 if (!size) {231 if (!size) 206 232 return EPERM; 207 }208 233 IPC_SET_ARG2(call->data, size); 209 234 break; … … 214 239 } 215 240 216 /****************************************************/ 217 /* Functions called to process received call/answer 218 * before passing to uspace 219 */ 220 221 /** Do basic kernel processing of received call answer */ 241 /******************************************************************************* 242 * Functions called to process received call/answer before passing it to uspace. 243 *******************************************************************************/ 244 245 /** Do basic kernel processing of received call answer. 246 * 247 * @param call Call structure with the answer. 248 */ 222 249 static void process_answer(call_t *call) 223 250 { … … 234 261 } 235 262 236 /** Do basic kernel processing of received call request 237 * 238 * @return 0 - the call should be passed to userspace, 1 - ignore call 263 /** Do basic kernel processing of received call request. 264 * 265 * @param box Destination answerbox structure. 266 * @param call Call structure with the request. 267 * 268 * @return Return 0 if the call should be passed to userspace. 269 * Return -1 if the call should be ignored. 239 270 */ 240 271 static int process_request(answerbox_t *box, call_t *call) … … 246 277 if (phoneid < 0) { /* Failed to allocate phone */ 247 278 IPC_SET_RETVAL(call->data, ELIMIT); 248 ipc_answer(box, call);279 ipc_answer(box, call); 249 280 return -1; 250 281 } … … 254 285 } 255 286 256 /** Send a call over IPC, wait for reply, return to user 257 * 258 * @return Call identification, returns -1 on fatal error, 259 -2 on 'Too many async request, handle answers first 287 /** Make a fast call over IPC, wait for reply and return to user. 288 * 289 * This function can handle only one argument of payload, but is faster than 290 * the generic function (i.e. sys_ipc_call_sync()). 291 * 292 * @param phoneid Phone handle for the call. 293 * @param method Method of the call. 294 * @param arg1 Service-defined payload argument. 295 * @param data Address of userspace structure where the reply call will 296 * be stored. 297 * 298 * @return Returns 0 on success. 299 * Return ENOENT if there is no such phone handle. 260 300 */ 261 301 unative_t sys_ipc_call_sync_fast(unative_t phoneid, unative_t method, … … 272 312 IPC_SET_ARG1(call.data, arg1); 273 313 274 if (!(res =request_preprocess(&call))) {314 if (!(res = request_preprocess(&call))) { 275 315 ipc_call_sync(phone, &call); 276 316 process_answer(&call); 277 } else 317 } else { 278 318 IPC_SET_RETVAL(call.data, res); 319 } 279 320 STRUCT_TO_USPACE(&data->args, &call.data.args); 280 321 … … 282 323 } 283 324 284 /** Synchronous IPC call allowing to send whole message */ 325 /** Make a synchronous IPC call allowing to transmit the entire payload. 326 * 327 * @param phoneid Phone handle for the call. 328 * @param question Userspace address of call data with the request. 329 * @param reply Userspace address of call data where to store the answer. 330 * 331 * @return Zero on success or an error code. 332 */ 285 333 unative_t sys_ipc_call_sync(unative_t phoneid, ipc_data_t *question, 286 334 ipc_data_t *reply) … … 299 347 GET_CHECK_PHONE(phone, phoneid, return ENOENT); 300 348 301 if (!(res =request_preprocess(&call))) {349 if (!(res = request_preprocess(&call))) { 302 350 ipc_call_sync(phone, &call); 303 351 process_answer(&call); … … 312 360 } 313 361 314 /** Check that the task did not exceed allowed limit315 * 316 * @return 0 - Limit OK, -1 - limit exceeded362 /** Check that the task did not exceed the allowed limit of asynchronous calls. 363 * 364 * @return Return 0 if limit not reached or -1 if limit exceeded. 317 365 */ 318 366 static int check_call_limit(void) … … 325 373 } 326 374 327 /** Send an asynchronous call over ipc 328 * 329 * @return Call identification, returns -1 on fatal error, 330 -2 on 'Too many async request, handle answers first 375 /** Make a fast asynchronous call over IPC. 376 * 377 * This function can only handle two arguments of payload, but is faster than 378 * the generic function sys_ipc_call_async(). 379 * 380 * @param phoneid Phone handle for the call. 381 * @param method Method of the call. 382 * @param arg1 Service-defined payload argument. 383 * @param arg2 Service-defined payload argument. 384 * 385 * @return Return call hash on success. 386 * Return IPC_CALLRET_FATAL in case of a fatal error and 387 * IPC_CALLRET_TEMPORARY if there are too many pending 388 * asynchronous requests; answers should be handled first. 331 389 */ 332 390 unative_t sys_ipc_call_async_fast(unative_t phoneid, unative_t method, … … 356 414 } 357 415 358 /** Synchronous IPC call allowing to send whole message 359 * 360 * @return The same as sys_ipc_call_async 416 /** Make an asynchronous IPC call allowing to transmit the entire payload. 417 * 418 * @param phoneid Phone handle for the call. 419 * @param data Userspace address of call data with the request. 420 * 421 * @return See sys_ipc_call_async_fast(). 361 422 */ 362 423 unative_t sys_ipc_call_async(unative_t phoneid, ipc_data_t *data) … … 387 448 } 388 449 389 /** Forward received call to another destination 390 * 391 * The arg1 and arg2 are changed in the forwarded message 450 /** Forward a received call to another destination. 451 * 452 * @param callid Hash of the call to forward. 453 * @param phoneid Phone handle to use for forwarding. 454 * @param method New method to use for the forwarded call. 455 * @param arg1 New value of the first argument for the forwarded call. 456 * 457 * @return Return 0 on succes, otherwise return an error code. 458 * 459 * In case the original method is a system method, ARG1 and ARG2 are overwritten 460 * in the forwarded message with the new method and the new arg1, respectively. 461 * Otherwise the METHOD and ARG1 are rewritten with the new method and arg1, 462 * respectively. 392 463 * 393 464 * Warning: If implementing non-fast version, make sure that 394 * arg3 is not rewritten for certain system IPC465 * ARG3 is not rewritten for certain system IPC 395 466 */ 396 467 unative_t sys_ipc_forward_fast(unative_t callid, unative_t phoneid, … … 435 506 } 436 507 437 /** Send IPC answer */ 508 /** Answer an IPC call - fast version. 509 * 510 * This function can handle only two return arguments of payload, but is faster 511 * than the generic sys_ipc_answer(). 512 * 513 * @param callid Hash of the call to be answered. 514 * @param retval Return value of the answer. 515 * @param arg1 Service-defined return value. 516 * @param arg2 Service-defined return value. 517 * 518 * @return Return 0 on success, otherwise return an error code. 519 */ 438 520 unative_t sys_ipc_answer_fast(unative_t callid, unative_t retval, 439 521 unative_t arg1, unative_t arg2) … … 466 548 } 467 549 468 /** Send IPC answer */ 550 /** Answer an IPC call. 551 * 552 * @param callid Hash of the call to be answered. 553 * @param data Userspace address of call data with the answer. 554 * 555 * @return Return 0 on success, otherwise return an error code. 556 */ 469 557 unative_t sys_ipc_answer(unative_t callid, ipc_data_t *data) 470 558 { … … 498 586 } 499 587 500 /** Hang up the phone 501 * 588 /** Hang up a phone. 589 * 590 * @param Phone handle of the phone to be hung up. 591 * 592 * @return Return 0 on success or an error code. 502 593 */ 503 594 unative_t sys_ipc_hangup(int phoneid) … … 513 604 } 514 605 515 /** Wait for incoming ipc call or answer606 /** Wait for an incoming IPC call or an answer. 516 607 * 517 608 * @param calldata Pointer to buffer where the call/answer data is stored. … … 520 611 * for explanation. 521 612 * 522 * @return Callid, if callid & 1, then the call is answer 613 * @return Hash of the call. 614 * If IPC_CALLID_NOTIFICATION bit is set in the hash, the 615 * call is a notification. IPC_CALLID_ANSWERED denotes an 616 * answer. 523 617 */ 524 618 unative_t sys_ipc_wait_for_call(ipc_data_t *calldata, uint32_t usec, int flags) … … 542 636 ipc_call_free(call); 543 637 544 return ((unative_t) call) | IPC_CALLID_NOTIFICATION;638 return ((unative_t) call) | IPC_CALLID_NOTIFICATION; 545 639 } 546 640 … … 560 654 ipc_call_free(call); 561 655 562 return ((unative_t) call) | IPC_CALLID_ANSWERED;656 return ((unative_t) call) | IPC_CALLID_ANSWERED; 563 657 } 564 658 … … 574 668 } 575 669 576 /** Connect irq handler totask.577 * 578 * @param inr 579 * @param devno 580 * @param method 581 * @param ucode 582 * 583 * @return 670 /** Connect an IRQ handler to a task. 671 * 672 * @param inr IRQ number. 673 * @param devno Device number. 674 * @param method Method to be associated with the notification. 675 * @param ucode Uspace pointer to the top-half pseudocode. 676 * 677 * @return EPERM or a return code returned by ipc_irq_register(). 584 678 */ 585 679 unative_t sys_ipc_register_irq(inr_t inr, devno_t devno, unative_t method, … … 592 686 } 593 687 594 /** Disconnect irq handler from task. 595 * 596 * @param inr IRQ number. 597 * @param devno Device number. 688 /** Disconnect an IRQ handler from a task. 689 * 690 * @param inr IRQ number. 691 * @param devno Device number. 692 * 693 * @return Zero on success or EPERM on error.. 598 694 */ 599 695 unative_t sys_ipc_unregister_irq(inr_t inr, devno_t devno) -
uspace/libc/generic/ipc.c
r4680ef5 r8b243f2 52 52 #include <psthread.h> 53 53 54 /** Structure used for keeping track of sent async msgs 55 * and queing unsent msgs 56 * 54 /** Structure used for keeping track of sent asynchronous calls and queing 55 * unsent calls. 57 56 */ 58 57 typedef struct { … … 67 66 int phoneid; 68 67 } msg; 69 } u;70 pstid_t ptid; /**< Thread waiting for sending this msg*/68 } u; 69 pstid_t ptid; /**< Pseudothread waiting for sending this call. */ 71 70 } async_call_t; 72 71 73 72 LIST_INITIALIZE(dispatched_calls); 74 73 75 /* queued_calls is protcted by async_futex, because if the76 * call cannot be sent into kernel, async framework is used77 * automatically78 * /79 LIST_INITIALIZE(queued_calls); /**< List of async calls that were not accepted 80 * by kernel */ 74 /** List of asynchronous calls that were not accepted by kernel. 75 * 76 * It is protected by async_futex, because if the call cannot be sent into the 77 * kernel, the async framework is used automatically. 78 */ 79 LIST_INITIALIZE(queued_calls); 81 80 82 81 static atomic_t ipc_futex = FUTEX_INITIALIZER; 83 82 84 int ipc_call_sync(int phoneid, ipcarg_t method, ipcarg_t arg1, 85 ipcarg_t *result) 83 /** Make a fast synchronous call. 84 * 85 * Only one payload argument can be passed using this function. However, this 86 * function is faster than the generic ipc_call_sync_3(). 87 * 88 * @param phoneid Phone handle for the call. 89 * @param method Requested method. 90 * @param arg1 Service-defined payload argument. 91 * @param result If non-NULL, the return ARG1 will be stored there. 92 * 93 * @return Negative values represent errors returned by IPC. 94 * Otherwise the RETVAL of the answer is returned. 95 */ 96 int ipc_call_sync(int phoneid, ipcarg_t method, ipcarg_t arg1, ipcarg_t *result) 86 97 { 87 98 ipc_call_t resdata; … … 89 100 90 101 callres = __SYSCALL4(SYS_IPC_CALL_SYNC_FAST, phoneid, method, arg1, 91 (sysarg_t)&resdata);102 (sysarg_t) &resdata); 92 103 if (callres) 93 104 return callres; … … 97 108 } 98 109 99 int ipc_call_sync_3(int phoneid, ipcarg_t method, ipcarg_t arg1, 100 ipcarg_t arg2, ipcarg_t arg3, 101 ipcarg_t *result1, ipcarg_t *result2, ipcarg_t *result3) 110 /** Make a synchronous call transmitting 3 arguments of payload. 111 * 112 * @param phoneid Phone handle for the call. 113 * @param method Requested method. 114 * @param arg1 Service-defined payload argument. 115 * @param arg2 Service-defined payload argument. 116 * @param arg3 Service-defined payload argument. 117 * @param result1 If non-NULL, storage for the first return argument. 118 * @param result2 If non-NULL, storage for the second return argument. 119 * @param result3 If non-NULL, storage for the third return argument. 120 * 121 * @return Negative value means IPC error. 122 * Otherwise the RETVAL of the answer. 123 */ 124 int ipc_call_sync_3(int phoneid, ipcarg_t method, ipcarg_t arg1, ipcarg_t arg2, 125 ipcarg_t arg3, ipcarg_t *result1, ipcarg_t *result2, ipcarg_t *result3) 102 126 { 103 127 ipc_call_t data; … … 109 133 IPC_SET_ARG3(data, arg3); 110 134 111 callres = __SYSCALL3(SYS_IPC_CALL_SYNC, phoneid, (sysarg_t) &data,112 (sysarg_t)&data);135 callres = __SYSCALL3(SYS_IPC_CALL_SYNC, phoneid, (sysarg_t) &data, 136 (sysarg_t) &data); 113 137 if (callres) 114 138 return callres; … … 123 147 } 124 148 125 /** Syscall to send asynchronous message */ 126 static ipc_callid_t _ipc_call_async(int phoneid, ipc_call_t *data) 127 { 128 return __SYSCALL2(SYS_IPC_CALL_ASYNC, phoneid, (sysarg_t)data); 129 } 130 131 /** Prolog to ipc_async_send functions */ 132 static inline async_call_t *ipc_prepare_async(void *private, ipc_async_callback_t callback) 149 /** Syscall to send asynchronous message. 150 * 151 * @param phoneid Phone handle for the call. 152 * @param data Call data with the request. 153 * 154 * @return Hash of the call or an error code. 155 */ 156 static ipc_callid_t _ipc_call_async(int phoneid, ipc_call_t *data) 157 { 158 return __SYSCALL2(SYS_IPC_CALL_ASYNC, phoneid, (sysarg_t) data); 159 } 160 161 /** Prolog to ipc_call_async_*() functions. 162 * 163 * @param private Argument for the answer/error callback. 164 * @param callback Answer/error callback. 165 * 166 * @return New, partially initialized async_call structure or NULL. 167 */ 168 static inline async_call_t *ipc_prepare_async(void *private, 169 ipc_async_callback_t callback) 133 170 { 134 171 async_call_t *call; … … 146 183 } 147 184 148 /** Epilogue of ipc_async_send functions */ 149 static inline void ipc_finish_async(ipc_callid_t callid, int phoneid, 150 async_call_t *call, int can_preempt) 185 /** Epilogue of ipc_call_async_*() functions. 186 * 187 * @param callid Value returned by the SYS_IPC_CALL_ASYNC_* syscall. 188 * @param phoneid Phone handle through which the call was made. 189 * @param call async_call structure returned by ipc_prepare_async(). 190 * @param can_preempt If non-zero, the current pseudo thread can be preempted 191 * in this call. 192 */ 193 static inline void ipc_finish_async(ipc_callid_t callid, int phoneid, 194 async_call_t *call, int can_preempt) 151 195 { 152 196 if (!call) { /* Nothing to do regardless if failed or not */ … … 183 227 } 184 228 call->u.callid = callid; 185 /* Add call to list of dispatched calls */229 /* Add call to the list of dispatched calls */ 186 230 list_append(&call->list, &dispatched_calls); 187 231 futex_up(&ipc_futex); … … 189 233 } 190 234 191 /** Send asynchronous message 192 * 193 * - if fatal error, call callback handler with proper error code 194 * - if message cannot be temporarily sent, add to queue 235 /** Make a fast asynchronous call. 236 * 237 * This function can only handle two arguments of payload. It is, however, 238 * faster than the more generic ipc_call_async_3(). 239 * 240 * Note that this function is a void function. 241 * During normal opertation, answering this call will trigger the callback. 242 * In case of fatal error, call the callback handler with the proper error code. 243 * If the call cannot be temporarily made, queue it. 244 * 245 * @param phoneid Phone handle for the call. 246 * @param method Requested method. 247 * @param arg1 Service-defined payload argument. 248 * @param arg2 Service-defined payload argument. 249 * @param private Argument to be passed to the answer/error callback. 250 * @param callback Answer or error callback. 251 * @param can_preempt If non-zero, the current pseudo thread will be preempted 252 * in case the kernel temporarily refuses to accept more 253 * asynchronous calls. 195 254 */ 196 255 void ipc_call_async_2(int phoneid, ipcarg_t method, ipcarg_t arg1, 197 ipcarg_t arg2, void *private,198 ipc_async_callback_t callback,int can_preempt)256 ipcarg_t arg2, void *private, ipc_async_callback_t callback, 257 int can_preempt) 199 258 { 200 259 async_call_t *call = NULL; … … 207 266 } 208 267 209 /* We need to make sure that we get callid before 210 * another thread accesses the queue again */ 268 /* 269 * We need to make sure that we get callid before another thread 270 * accesses the queue again. 271 */ 211 272 futex_down(&ipc_futex); 212 callid = __SYSCALL4(SYS_IPC_CALL_ASYNC_FAST, phoneid, method, arg1, arg2); 273 callid = __SYSCALL4(SYS_IPC_CALL_ASYNC_FAST, phoneid, method, arg1, 274 arg2); 213 275 214 276 if (callid == IPC_CALLRET_TEMPORARY) { … … 225 287 } 226 288 227 /** Send asynchronous message 228 * 229 * - if fatal error, call callback handler with proper error code 230 * - if message cannot be temporarily sent, add to queue 289 /** Make an asynchronous call transmitting the entire payload. 290 * 291 * Note that this function is a void function. 292 * During normal opertation, answering this call will trigger the callback. 293 * In case of fatal error, call the callback handler with the proper error code. 294 * If the call cannot be temporarily made, queue it. 295 * 296 * @param phoneid Phone handle for the call. 297 * @param method Requested method. 298 * @param arg1 Service-defined payload argument. 299 * @param arg2 Service-defined payload argument. 300 * @param arg3 Service-defined payload argument. 301 * @param private Argument to be passed to the answer/error callback. 302 * @param callback Answer or error callback. 303 * @param can_preempt If non-zero, the current pseudo thread will be preempted 304 * in case the kernel temporarily refuses to accept more 305 * asynchronous calls. 306 * 231 307 */ 232 308 void ipc_call_async_3(int phoneid, ipcarg_t method, ipcarg_t arg1, 233 ipcarg_t arg2, ipcarg_t arg3, void *private,234 ipc_async_callback_t callback,int can_preempt)309 ipcarg_t arg2, ipcarg_t arg3, void *private, ipc_async_callback_t callback, 310 int can_preempt) 235 311 { 236 312 async_call_t *call; … … 245 321 IPC_SET_ARG2(call->u.msg.data, arg2); 246 322 IPC_SET_ARG3(call->u.msg.data, arg3); 247 /* We need to make sure that we get callid before 248 * another thread accesses the queue again */ 323 /* 324 * We need to make sure that we get callid before another thread accesses 325 * the queue again. 326 */ 249 327 futex_down(&ipc_futex); 250 328 callid = _ipc_call_async(phoneid, &call->u.msg.data); … … 254 332 255 333 256 /** Send a fast answer to a received call.257 * 258 * The fast answer makes use of passing retval and first two arguments in registers.259 * If you need to return more, use the ipc_answer() instead.260 * 261 * @param callid IDof the call being answered.262 * @param retval 263 * @param arg1 264 * @param arg2 265 * 266 * @return 334 /** Answer a received call - fast version. 335 * 336 * The fast answer makes use of passing retval and first two arguments in 337 * registers. If you need to return more, use the ipc_answer() instead. 338 * 339 * @param callid Hash of the call being answered. 340 * @param retval Return value. 341 * @param arg1 First return argument. 342 * @param arg2 Second return argument. 343 * 344 * @return Zero on success or a value from @ref errno.h on failure. 267 345 */ 268 346 ipcarg_t ipc_answer_fast(ipc_callid_t callid, ipcarg_t retval, ipcarg_t arg1, 269 347 ipcarg_t arg2) 270 348 { 271 349 return __SYSCALL4(SYS_IPC_ANSWER_FAST, callid, retval, arg1, arg2); 272 350 } 273 351 274 /** Send a full answer to a received call. 275 * 276 * @param callid ID of the call being answered. 277 * @param call Call data. Must be already initialized by the responder. 278 * 279 * @return Zero on success or a value from @ref errno.h on failure. 352 /** Answer a received call - full version. 353 * 354 * @param callid Hash of the call being answered. 355 * @param call Call structure with the answer. 356 * Must be already initialized by the responder. 357 * 358 * @return Zero on success or a value from @ref errno.h on failure. 280 359 */ 281 360 ipcarg_t ipc_answer(ipc_callid_t callid, ipc_call_t *call) … … 285 364 286 365 287 /** Try to dispatch que ed calls from async queue*/366 /** Try to dispatch queued calls from the async queue. */ 288 367 static void try_dispatch_queued_calls(void) 289 368 { … … 291 370 ipc_callid_t callid; 292 371 293 /* TODO: integrate intelligently ipc_futex, so that it294 * is locked during ipc_call_async, until it is added295 * to dispatched_calls372 /** @todo 373 * Integrate intelligently ipc_futex, so that it is locked during 374 * ipc_call_async_*(), until it is added to dispatched_calls. 296 375 */ 297 376 futex_down(&async_futex); 298 377 while (!list_empty(&queued_calls)) { 299 call = list_get_instance(queued_calls.next, async_call_t, 300 list); 301 302 callid = _ipc_call_async(call->u.msg.phoneid, 303 &call->u.msg.data); 378 call = list_get_instance(queued_calls.next, async_call_t, list); 379 callid = _ipc_call_async(call->u.msg.phoneid, &call->u.msg.data); 304 380 if (callid == IPC_CALLRET_TEMPORARY) { 305 381 break; … … 326 402 } 327 403 328 /** Handle received answer 329 * 330 * TODO: Make it use hash table 331 * 332 * @param callid Callid (with first bit set) of the answered call 404 /** Handle a received answer. 405 * 406 * Find the hash of the answer and call the answer callback. 407 * 408 * @todo Make it use hash table. 409 * 410 * @param callid Hash of the received answer. 411 * The answer has the same hash as the request OR'ed with 412 * the IPC_CALLID_ANSWERED bit. 413 * @param data Call data of the answer. 333 414 */ 334 415 static void handle_answer(ipc_callid_t callid, ipc_call_t *data) … … 341 422 futex_down(&ipc_futex); 342 423 for (item = dispatched_calls.next; item != &dispatched_calls; 343 424 item = item->next) { 344 425 call = list_get_instance(item, async_call_t, list); 345 426 if (call->u.callid == callid) { … … 348 429 if (call->callback) 349 430 call->callback(call->private, 350 IPC_GET_RETVAL(*data), 351 data); 431 IPC_GET_RETVAL(*data), data); 352 432 free(call); 353 433 return; … … 355 435 } 356 436 futex_up(&ipc_futex); 357 /* We may get here after async_msg, which doesn't register any callback */ 358 } 359 360 361 /** One cycle of ipc wait for call call 362 * 363 * - dispatch ASYNC reoutines in the background 364 * @param call Space where the message is stored 365 * @param usec Timeout in microseconds 366 * @param flags Flags passed to SYS_IPC_WAIT (blocking, nonblocking) 367 * @return Callid of the answer. 437 } 438 439 440 /** Wait for a first call to come. 441 * 442 * @param call Storage where the incoming call data will be stored. 443 * @param usec Timeout in microseconds 444 * @param flags Flags passed to SYS_IPC_WAIT (blocking, nonblocking). 445 * 446 * @return Hash of the call. Note that certain bits have special 447 * meaning. IPC_CALLID_ANSWERED will be set in an answer 448 * and IPC_CALLID_NOTIFICATION is used for notifications. 449 * 368 450 */ 369 451 ipc_callid_t ipc_wait_cycle(ipc_call_t *call, uint32_t usec, int flags) … … 383 465 /** Wait some time for an IPC call. 384 466 * 385 * - dispatch ASYNC reoutines in the background 386 * 387 * @param call Space where the message is stored 388 * @param usec Timeout in microseconds. 389 * @return Callid of the answer. 467 * The call will return after an answer is received. 468 * 469 * @param call Storage where the incoming call data will be stored. 470 * @param usec Timeout in microseconds. 471 * 472 * @return Hash of the answer. 390 473 */ 391 474 ipc_callid_t ipc_wait_for_call_timeout(ipc_call_t *call, uint32_t usec) … … 402 485 /** Check if there is an IPC call waiting to be picked up. 403 486 * 404 * - dispatch ASYNC reoutines in the background 405 * 406 * @param call Space where the message is stored 407 * @return Callid of the answer. 487 * @param call Storage where the incoming call will be stored. 488 * @return Hash of the answer. 408 489 */ 409 490 ipc_callid_t ipc_trywait_for_call(ipc_call_t *call) … … 412 493 413 494 do { 414 callid = ipc_wait_cycle(call, SYNCH_NO_TIMEOUT, SYNCH_FLAGS_NON_BLOCKING); 495 callid = ipc_wait_cycle(call, SYNCH_NO_TIMEOUT, 496 SYNCH_FLAGS_NON_BLOCKING); 415 497 } while (callid & IPC_CALLID_ANSWERED); 416 498 … … 420 502 /** Ask destination to do a callback connection. 421 503 * 422 * @param phoneid Phone ID used for contacting the other side. 504 * @param phoneid Phone handle used for contacting the other side. 505 * @param arg1 Service-defined argument. 506 * @param arg2 Service-defined argument. 507 * @param phonehash Storage where the library will store an opaque 508 * identifier of the phone that will be used for incoming 509 * calls. This identifier can be used for connection 510 * tracking. 511 * 512 * @return Zero on success or a negative error code. 513 */ 514 int ipc_connect_to_me(int phoneid, int arg1, int arg2, ipcarg_t *phonehash) 515 { 516 return ipc_call_sync_3(phoneid, IPC_M_CONNECT_TO_ME, arg1, arg2, 0, 0, 0, 517 phonehash); 518 } 519 520 /** Ask through phone for a new connection to some service. 521 * 522 * @param phoneid Phone handle used for contacting the other side. 423 523 * @param arg1 User defined argument. 424 524 * @param arg2 User defined argument. 425 * @param phonehash Pointer to a place where the library will store an opaque 426 * identifier of the phone that will be used for incoming 427 * calls. 428 * @return Zero on success or a negative error code. 429 */ 430 int ipc_connect_to_me(int phoneid, int arg1, int arg2, ipcarg_t *phonehash) 431 { 432 return ipc_call_sync_3(phoneid, IPC_M_CONNECT_TO_ME, arg1, arg2, 0, 0, 0, 433 phonehash); 434 } 435 436 /** Ask through phone for a new connection to some service. 437 * 438 * @param phoneid Phone ID used for contacting the other side. 439 * @param arg1 User defined argument. 440 * @param arg2 User defined argument. 441 * 442 * @return New phone ID on success or a negative error code. 525 * 526 * @return New phone handle on success or a negative error code. 443 527 */ 444 528 int ipc_connect_me_to(int phoneid, int arg1, int arg2) … … 454 538 } 455 539 456 /* Hang up specified phone */ 540 /** Hang up a phone. 541 * 542 * @param phoneid Handle of the phone to be hung up. 543 * 544 * @return Zero on success or a negative error code. 545 */ 457 546 int ipc_hangup(int phoneid) 458 547 { … … 462 551 /** Register IRQ notification. 463 552 * 464 * @param inr 465 * @param devno 466 * @param method 467 * @param ucode 468 * 469 * @return 553 * @param inr IRQ number. 554 * @param devno Device number of the device generating inr. 555 * @param method Use this method for notifying me. 556 * @param ucode Top-half pseudocode handler. 557 * 558 * @return Value returned by the kernel. 470 559 */ 471 560 int ipc_register_irq(int inr, int devno, int method, irq_code_t *ucode) 472 561 { 473 return __SYSCALL4(SYS_IPC_REGISTER_IRQ, inr, devno, method, (sysarg_t) ucode); 562 return __SYSCALL4(SYS_IPC_REGISTER_IRQ, inr, devno, method, 563 (sysarg_t) ucode); 474 564 } 475 565 476 566 /** Unregister IRQ notification. 477 567 * 478 * @param inr 479 * @param devno 480 * 481 * @return 568 * @param inr IRQ number. 569 * @param devno Device number of the device generating inr. 570 * 571 * @return Value returned by the kernel. 482 572 */ 483 573 int ipc_unregister_irq(int inr, int devno) … … 486 576 } 487 577 578 /** Forward a received call to another destination. 579 * 580 * @param callid Hash of the call to forward. 581 * @param phoneid Phone handle to use for forwarding. 582 * @param method New method for the forwarded call. 583 * @param arg1 New value of the first argument for the forwarded call. 584 * 585 * @return Zero on success or an error code. 586 * 587 * For non-system methods, the old method and arg1 are rewritten by the new 588 * values. For system methods, the new method and arg1 are written to the old 589 * arg1 and arg2, respectivelly. 590 */ 488 591 int ipc_forward_fast(ipc_callid_t callid, int phoneid, int method, ipcarg_t arg1) 489 592 { -
uspace/libc/include/ipc/ipc.h
r4680ef5 r8b243f2 50 50 51 51 typedef void (* ipc_async_callback_t)(void *private, int retval, 52 52 ipc_call_t *data); 53 53 54 #define ipc_call_sync_2(phoneid, method, arg1, arg2, res1, res2) ipc_call_sync_3((phoneid), (method), (arg1), (arg2), 0, (res1), (res2), 0) 54 #define ipc_call_sync_2(phoneid, method, arg1, arg2, res1, res2) \ 55 ipc_call_sync_3((phoneid), (method), (arg1), (arg2), 0, (res1), (res2), \ 56 0) 55 57 extern int ipc_call_sync_3(int phoneid, ipcarg_t method, ipcarg_t arg1, 56 ipcarg_t arg2, ipcarg_t arg3, 57 ipcarg_t *result1, ipcarg_t *result2, 58 ipcarg_t *result3); 59 58 ipcarg_t arg2, ipcarg_t arg3, ipcarg_t *result1, ipcarg_t *result2, 59 ipcarg_t *result3); 60 60 61 61 extern int ipc_call_sync(int phoneid, ipcarg_t method, ipcarg_t arg1, 62 ipcarg_t *result); 62 ipcarg_t *result); 63 63 64 extern ipc_callid_t ipc_wait_cycle(ipc_call_t *call, uint32_t usec, int flags); 64 65 extern ipc_callid_t ipc_wait_for_call_timeout(ipc_call_t *data, uint32_t usec); … … 69 70 extern ipc_callid_t ipc_trywait_for_call(ipc_call_t *data); 70 71 71 extern ipcarg_t ipc_answer_fast(ipc_callid_t callid, ipcarg_t retval, ipcarg_t arg1,72 72 extern ipcarg_t ipc_answer_fast(ipc_callid_t callid, ipcarg_t retval, 73 ipcarg_t arg1, ipcarg_t arg2); 73 74 extern ipcarg_t ipc_answer(ipc_callid_t callid, ipc_call_t *call); 74 75 75 #define ipc_call_async(phoneid,method,arg1,private, callback,can_preempt) (ipc_call_async_2(phoneid, method, arg1, 0, private, callback, can_preempt)) 76 #define ipc_call_async(phoneid, method, arg1, private, callback, can_preempt) \ 77 (ipc_call_async_2(phoneid, method, arg1, 0, private, callback, \ 78 can_preempt)) 76 79 extern void ipc_call_async_2(int phoneid, ipcarg_t method, ipcarg_t arg1, 77 ipcarg_t arg2, void *private,78 ipc_async_callback_t callback,int can_preempt);80 ipcarg_t arg2, void *private, ipc_async_callback_t callback, 81 int can_preempt); 79 82 extern void ipc_call_async_3(int phoneid, ipcarg_t method, ipcarg_t arg1, 80 ipcarg_t arg2, ipcarg_t arg3, void *private,81 ipc_async_callback_t callback,int can_preempt);83 ipcarg_t arg2, ipcarg_t arg3, void *private, ipc_async_callback_t callback, 84 int can_preempt); 82 85 83 86 extern int ipc_connect_to_me(int phoneid, int arg1, int arg2, ipcarg_t *phone); … … 86 89 extern int ipc_register_irq(int inr, int devno, int method, irq_code_t *code); 87 90 extern int ipc_unregister_irq(int inr, int devno); 88 extern int ipc_forward_fast(ipc_callid_t callid, int phoneid, int method, ipcarg_t arg1); 91 extern int ipc_forward_fast(ipc_callid_t callid, int phoneid, int method, 92 ipcarg_t arg1); 89 93 90 94 #endif -
uspace/ns/ns.c
r4680ef5 r8b243f2 156 156 * 157 157 * @param service Service to be registered. 158 * @param phone phonePhone to be used for connections to the service.158 * @param phone Phone to be used for connections to the service. 159 159 * @param call Pointer to call structure. 160 160 * -
uspace/pci/pci.c
r4680ef5 r8b243f2 2 2 * HelenOS PCI driver. 3 3 * 4 * Copyright (c) 1997-2003 Martin Mares4 * (Based on public domain libpci example.c written by Martin Mares.) 5 5 * Copyright (c) 2006 Jakub Jermar 6 *7 * (Based on libpci example.c written by Martin Mares.)8 6 * 9 7 * Can be freely distributed and used under the terms of the GNU GPL. -
uspace/rd/rd.c
r4680ef5 r8b243f2 67 67 callid = async_get_call(&call); 68 68 switch (IPC_GET_METHOD(call)) { 69 70 ipc_answer_fast(callid, 0,0,0);71 72 73 ipc_answer_fast(callid, 0, (uintptr_t)fs_addr, 0);74 75 76 77 memcpy((void *)fs_addr, rd_addr+offset, BLOCK_SIZE);78 79 80 81 69 case IPC_M_PHONE_HUNGUP: 70 ipc_answer_fast(callid, 0, 0, 0); 71 return; 72 case IPC_M_AS_AREA_SEND: 73 ipc_answer_fast(callid, 0, (uintptr_t) fs_addr, 0); 74 continue; 75 case RD_READ_BLOCK: 76 offset = IPC_GET_ARG1(call); 77 memcpy((void *) fs_addr, rd_addr + offset, BLOCK_SIZE); 78 retval = EOK; 79 break; 80 default: 81 retval = EINVAL; 82 82 } 83 83 ipc_answer_fast(callid, retval, 0, 0); 84 } 84 } 85 85 } 86 86 … … 91 91 92 92 size_t rd_size = sysinfo_value("rd.size"); 93 void * 93 void *rd_ph_addr = (void *) sysinfo_value("rd.address.physical"); 94 94 95 95 if (rd_size == 0) … … 99 99 100 100 flags = AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE; 101 retval = physmem_map(rd_ph_addr, rd_addr, ALIGN_UP(rd_size, PAGE_SIZE) >> PAGE_WIDTH, flags); 101 retval = physmem_map(rd_ph_addr, rd_addr, 102 ALIGN_UP(rd_size, PAGE_SIZE) >> PAGE_WIDTH, flags); 102 103 103 104 if (retval < 0)
Note:
See TracChangeset
for help on using the changeset viewer.