Changes in kernel/generic/src/ipc/irq.c [55b77d9:3cc070d] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
kernel/generic/src/ipc/irq.c
r55b77d9 r3cc070d 42 42 * 43 43 * The structure of a notification message is as follows: 44 * - IMETHOD: interface and method as registered by the SYS_REGISTER_IRQ45 * syscall44 * - IMETHOD: interface and method as registered by 45 * the SYS_IRQ_REGISTER syscall 46 46 * - ARG1: payload modified by a 'top-half' handler 47 47 * - ARG2: payload modified by a 'top-half' handler … … 74 74 #include <arch.h> 75 75 #include <mm/slab.h> 76 #include <mm/page.h> 77 #include <mm/km.h> 76 78 #include <errno.h> 77 79 #include <ddi/irq.h> … … 81 83 #include <console/console.h> 82 84 #include <print.h> 85 #include <macros.h> 86 87 static void ranges_unmap(irq_pio_range_t *ranges, size_t rangecount) 88 { 89 size_t i; 90 91 for (i = 0; i < rangecount; i++) { 92 #ifdef IO_SPACE_BOUNDARY 93 if ((void *) ranges[i].base >= IO_SPACE_BOUNDARY) 94 #endif 95 km_unmap(ranges[i].base, ranges[i].size); 96 } 97 } 98 99 static int ranges_map_and_apply(irq_pio_range_t *ranges, size_t rangecount, 100 irq_cmd_t *cmds, size_t cmdcount) 101 { 102 uintptr_t *pbase; 103 size_t i, j; 104 105 /* Copy the physical base addresses aside. */ 106 pbase = malloc(rangecount * sizeof(uintptr_t), 0); 107 for (i = 0; i < rangecount; i++) 108 pbase[i] = ranges[i].base; 109 110 /* Map the PIO ranges into the kernel virtual address space. */ 111 for (i = 0; i < rangecount; i++) { 112 #ifdef IO_SPACE_BOUNDARY 113 if ((void *) ranges[i].base < IO_SPACE_BOUNDARY) 114 continue; 115 #endif 116 ranges[i].base = km_map(pbase[i], ranges[i].size, 117 PAGE_READ | PAGE_WRITE | PAGE_KERNEL | PAGE_NOT_CACHEABLE); 118 if (!ranges[i].base) { 119 ranges_unmap(ranges, i); 120 free(pbase); 121 return ENOMEM; 122 } 123 } 124 125 /* Rewrite the pseudocode addresses from physical to kernel virtual. */ 126 for (i = 0; i < cmdcount; i++) { 127 uintptr_t addr; 128 size_t size; 129 130 /* Process only commands that use an address. */ 131 switch (cmds[i].cmd) { 132 case CMD_PIO_READ_8: 133 case CMD_PIO_WRITE_8: 134 case CMD_PIO_WRITE_A_8: 135 size = 1; 136 break; 137 case CMD_PIO_READ_16: 138 case CMD_PIO_WRITE_16: 139 case CMD_PIO_WRITE_A_16: 140 size = 2; 141 break; 142 case CMD_PIO_READ_32: 143 case CMD_PIO_WRITE_32: 144 case CMD_PIO_WRITE_A_32: 145 size = 4; 146 break; 147 default: 148 /* Move onto the next command. */ 149 continue; 150 } 151 152 addr = (uintptr_t) cmds[i].addr; 153 154 for (j = 0; j < rangecount; j++) { 155 156 /* Find the matching range. */ 157 if (!iswithin(pbase[j], ranges[j].size, addr, size)) 158 continue; 159 160 /* Switch the command to a kernel virtual address. */ 161 addr -= pbase[j]; 162 addr += ranges[j].base; 163 164 cmds[i].addr = (void *) addr; 165 break; 166 } 167 168 if (j == rangecount) { 169 /* 170 * The address used in this command is outside of all 171 * defined ranges. 172 */ 173 ranges_unmap(ranges, rangecount); 174 free(pbase); 175 return EINVAL; 176 } 177 } 178 179 free(pbase); 180 return EOK; 181 } 83 182 84 183 /** Free the top-half pseudocode. … … 90 189 { 91 190 if (code) { 191 ranges_unmap(code->ranges, code->rangecount); 192 free(code->ranges); 92 193 free(code->cmds); 93 194 free(code); … … 104 205 static irq_code_t *code_from_uspace(irq_code_t *ucode) 105 206 { 207 irq_pio_range_t *ranges = NULL; 208 irq_cmd_t *cmds = NULL; 209 106 210 irq_code_t *code = malloc(sizeof(*code), 0); 107 211 int rc = copy_from_uspace(code, ucode, sizeof(*code)); 108 if (rc != 0) { 109 free(code); 110 return NULL; 111 } 112 113 if (code->cmdcount > IRQ_MAX_PROG_SIZE) { 114 free(code); 115 return NULL; 116 } 117 118 irq_cmd_t *ucmds = code->cmds; 119 code->cmds = malloc(sizeof(code->cmds[0]) * code->cmdcount, 0); 120 rc = copy_from_uspace(code->cmds, ucmds, 212 if (rc != EOK) 213 goto error; 214 215 if ((code->rangecount > IRQ_MAX_RANGE_COUNT) || 216 (code->cmdcount > IRQ_MAX_PROG_SIZE)) 217 goto error; 218 219 ranges = malloc(sizeof(code->ranges[0]) * code->rangecount, 0); 220 rc = copy_from_uspace(ranges, code->ranges, 221 sizeof(code->ranges[0]) * code->rangecount); 222 if (rc != EOK) 223 goto error; 224 225 cmds = malloc(sizeof(code->cmds[0]) * code->cmdcount, 0); 226 rc = copy_from_uspace(cmds, code->cmds, 121 227 sizeof(code->cmds[0]) * code->cmdcount); 122 if (rc != 0) { 123 free(code->cmds); 124 free(code); 125 return NULL; 126 } 127 228 if (rc != EOK) 229 goto error; 230 231 rc = ranges_map_and_apply(ranges, code->rangecount, cmds, 232 code->cmdcount); 233 if (rc != EOK) 234 goto error; 235 236 code->ranges = ranges; 237 code->cmds = cmds; 238 128 239 return code; 240 241 error: 242 if (cmds) 243 free(cmds); 244 if (ranges) 245 free(ranges); 246 free(code); 247 return NULL; 129 248 } 130 249 … … 174 293 irq->notif_cfg.code = code; 175 294 irq->notif_cfg.counter = 0; 176 irq->driver_as = AS;177 295 178 296 /* … … 239 357 240 358 ASSERT(irq->notif_cfg.answerbox == box); 241 242 /* Free up the pseudo code and associated structures. */243 code_free(irq->notif_cfg.code);244 359 245 360 /* Remove the IRQ from the answerbox's list. */ … … 260 375 irq_spinlock_unlock(&box->irq_lock, false); 261 376 irq_spinlock_unlock(&irq_uspace_hash_table_lock, true); 377 378 /* Free up the pseudo code and associated structures. */ 379 code_free(irq->notif_cfg.code); 262 380 263 381 /* Free up the IRQ structure. */ … … 307 425 list_remove(&irq->notif_cfg.link); 308 426 309 /* Free up the pseudo code and associated structures. */310 code_free(irq->notif_cfg.code);311 312 427 /* 313 428 * We need to drop the IRQ lock now because hash_table_remove() … … 321 436 /* Remove from the hash table. */ 322 437 hash_table_remove(&irq_uspace_hash_table, key, 2); 323 438 439 /* 440 * Release both locks so that we can free the pseudo code. 441 */ 442 irq_spinlock_unlock(&box->irq_lock, false); 443 irq_spinlock_unlock(&irq_uspace_hash_table_lock, true); 444 445 code_free(irq->notif_cfg.code); 324 446 free(irq); 447 448 /* Reacquire both locks before taking another round. */ 449 irq_spinlock_lock(&irq_uspace_hash_table_lock, true); 450 irq_spinlock_lock(&box->irq_lock, false); 325 451 } 326 452 … … 365 491 return IRQ_DECLINE; 366 492 367 #define CMD_MEM_READ(target) \ 368 do { \ 369 void *va = code->cmds[i].addr; \ 370 if (AS != irq->driver_as) \ 371 as_switch(AS, irq->driver_as); \ 372 memcpy_from_uspace(&target, va, (sizeof(target))); \ 373 if (dstarg) \ 374 scratch[dstarg] = target; \ 375 } while(0) 376 377 #define CMD_MEM_WRITE(val) \ 378 do { \ 379 void *va = code->cmds[i].addr; \ 380 if (AS != irq->driver_as) \ 381 as_switch(AS, irq->driver_as); \ 382 memcpy_to_uspace(va, &val, sizeof(val)); \ 383 } while (0) 384 385 as_t *current_as = AS; 386 size_t i; 387 for (i = 0; i < code->cmdcount; i++) { 493 for (size_t i = 0; i < code->cmdcount; i++) { 388 494 uint32_t dstval; 495 389 496 uintptr_t srcarg = code->cmds[i].srcarg; 390 497 uintptr_t dstarg = code->cmds[i].dstarg; … … 442 549 } 443 550 break; 444 case CMD_MEM_READ_8: {445 uint8_t val;446 CMD_MEM_READ(val);447 break;448 }449 case CMD_MEM_READ_16: {450 uint16_t val;451 CMD_MEM_READ(val);452 break;453 }454 case CMD_MEM_READ_32: {455 uint32_t val;456 CMD_MEM_READ(val);457 break;458 }459 case CMD_MEM_WRITE_8: {460 uint8_t val = code->cmds[i].value;461 CMD_MEM_WRITE(val);462 break;463 }464 case CMD_MEM_WRITE_16: {465 uint16_t val = code->cmds[i].value;466 CMD_MEM_WRITE(val);467 break;468 }469 case CMD_MEM_WRITE_32: {470 uint32_t val = code->cmds[i].value;471 CMD_MEM_WRITE(val);472 break;473 }474 case CMD_MEM_WRITE_A_8:475 if (srcarg) {476 uint8_t val = scratch[srcarg];477 CMD_MEM_WRITE(val);478 }479 break;480 case CMD_MEM_WRITE_A_16:481 if (srcarg) {482 uint16_t val = scratch[srcarg];483 CMD_MEM_WRITE(val);484 }485 break;486 case CMD_MEM_WRITE_A_32:487 if (srcarg) {488 uint32_t val = scratch[srcarg];489 CMD_MEM_WRITE(val);490 }491 break;492 551 case CMD_BTEST: 493 552 if ((srcarg) && (dstarg)) { … … 503 562 break; 504 563 case CMD_ACCEPT: 505 if (AS != current_as)506 as_switch(AS, current_as);507 564 return IRQ_ACCEPT; 508 565 case CMD_DECLINE: 509 566 default: 510 if (AS != current_as)511 as_switch(AS, current_as);512 567 return IRQ_DECLINE; 513 568 } 514 569 } 515 if (AS != current_as)516 as_switch(AS, current_as);517 570 518 571 return IRQ_DECLINE;
Note:
See TracChangeset
for help on using the changeset viewer.