Changes in kernel/generic/src/ipc/irq.c [9d58539:8486c07] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
kernel/generic/src/ipc/irq.c
r9d58539 r8486c07 39 39 * when interrupt is detected. The application may provide a simple 'top-half' 40 40 * handler as part of its registration, which can perform simple operations 41 * (read/write port/memory, add information to notification ipcmessage).41 * (read/write port/memory, add information to notification IPC message). 42 42 * 43 43 * The structure of a notification message is as follows: 44 44 * - IMETHOD: interface and method as registered by 45 45 * the SYS_IRQ_REGISTER syscall 46 * - ARG1: payload modified by a 'top-half' handler 47 * - ARG2: payload modified by a 'top-half' handler 48 * - ARG3: payload modified by a 'top-half' handler 49 * - ARG4: payload modified by a 'top-half' handler 50 * - ARG5: payload modified by a 'top-half' handler 46 * - ARG1: payload modified by a 'top-half' handler (scratch[1]) 47 * - ARG2: payload modified by a 'top-half' handler (scratch[2]) 48 * - ARG3: payload modified by a 'top-half' handler (scratch[3]) 49 * - ARG4: payload modified by a 'top-half' handler (scratch[4]) 50 * - ARG5: payload modified by a 'top-half' handler (scratch[5]) 51 51 * - in_phone_hash: interrupt counter (may be needed to assure correct order 52 52 * in multithreaded drivers) … … 87 87 static void ranges_unmap(irq_pio_range_t *ranges, size_t rangecount) 88 88 { 89 size_t i; 90 91 for (i = 0; i < rangecount; i++) { 89 for (size_t i = 0; i < rangecount; i++) { 92 90 #ifdef IO_SPACE_BOUNDARY 93 91 if ((void *) ranges[i].base >= IO_SPACE_BOUNDARY) … … 100 98 irq_cmd_t *cmds, size_t cmdcount) 101 99 { 102 uintptr_t *pbase;103 size_t i, j;104 105 100 /* Copy the physical base addresses aside. */ 106 pbase = malloc(rangecount * sizeof(uintptr_t), 0);107 for ( i = 0; i < rangecount; i++)101 uintptr_t *pbase = malloc(rangecount * sizeof(uintptr_t), 0); 102 for (size_t i = 0; i < rangecount; i++) 108 103 pbase[i] = ranges[i].base; 109 104 110 105 /* Map the PIO ranges into the kernel virtual address space. */ 111 for ( i = 0; i < rangecount; i++) {106 for (size_t i = 0; i < rangecount; i++) { 112 107 #ifdef IO_SPACE_BOUNDARY 113 108 if ((void *) ranges[i].base < IO_SPACE_BOUNDARY) … … 122 117 } 123 118 } 124 119 125 120 /* Rewrite the pseudocode addresses from physical to kernel virtual. */ 126 for ( i = 0; i < cmdcount; i++) {121 for (size_t i = 0; i < cmdcount; i++) { 127 122 uintptr_t addr; 128 123 size_t size; 129 124 130 125 /* Process only commands that use an address. */ 131 126 switch (cmds[i].cmd) { 132 127 case CMD_PIO_READ_8: 133 134 128 case CMD_PIO_WRITE_8: 129 case CMD_PIO_WRITE_A_8: 135 130 size = 1; 136 131 break; 137 138 139 132 case CMD_PIO_READ_16: 133 case CMD_PIO_WRITE_16: 134 case CMD_PIO_WRITE_A_16: 140 135 size = 2; 141 136 break; 142 143 144 137 case CMD_PIO_READ_32: 138 case CMD_PIO_WRITE_32: 139 case CMD_PIO_WRITE_A_32: 145 140 size = 4; 146 141 break; … … 149 144 continue; 150 145 } 151 146 152 147 addr = (uintptr_t) cmds[i].addr; 153 148 149 size_t j; 154 150 for (j = 0; j < rangecount; j++) { 155 156 151 /* Find the matching range. */ 157 152 if (!iswithin(pbase[j], ranges[j].size, addr, size)) 158 153 continue; 159 154 160 155 /* Switch the command to a kernel virtual address. */ 161 156 addr -= pbase[j]; 162 157 addr += ranges[j].base; 163 158 164 159 cmds[i].addr = (void *) addr; 165 160 break; 166 161 } 167 162 168 163 if (j == rangecount) { 169 164 /* … … 176 171 } 177 172 } 178 173 179 174 free(pbase); 175 return EOK; 176 } 177 178 /** Statically check the top-half pseudocode 179 * 180 * Check the top-half pseudocode for invalid or unsafe 181 * constructs. 182 * 183 */ 184 static int code_check(irq_cmd_t *cmds, size_t cmdcount) 185 { 186 for (size_t i = 0; i < cmdcount; i++) { 187 /* 188 * Check for accepted ranges. 189 */ 190 if (cmds[i].cmd >= CMD_LAST) 191 return EINVAL; 192 193 if (cmds[i].srcarg >= IPC_CALL_LEN) 194 return EINVAL; 195 196 if (cmds[i].dstarg >= IPC_CALL_LEN) 197 return EINVAL; 198 199 switch (cmds[i].cmd) { 200 case CMD_PREDICATE: 201 /* 202 * Check for control flow overflow. 203 * Note that jumping just beyond the last 204 * command is a correct behaviour. 205 */ 206 if (i + cmds[i].value > cmdcount) 207 return EINVAL; 208 209 break; 210 default: 211 break; 212 } 213 } 214 180 215 return EOK; 181 216 } … … 207 242 irq_pio_range_t *ranges = NULL; 208 243 irq_cmd_t *cmds = NULL; 209 244 210 245 irq_code_t *code = malloc(sizeof(*code), 0); 211 246 int rc = copy_from_uspace(code, ucode, sizeof(*code)); … … 222 257 if (rc != EOK) 223 258 goto error; 224 259 225 260 cmds = malloc(sizeof(code->cmds[0]) * code->cmdcount, 0); 226 261 rc = copy_from_uspace(cmds, code->cmds, … … 228 263 if (rc != EOK) 229 264 goto error; 230 265 266 rc = code_check(cmds, code->cmdcount); 267 if (rc != EOK) 268 goto error; 269 231 270 rc = ranges_map_and_apply(ranges, code->rangecount, cmds, 232 271 code->cmdcount); 233 272 if (rc != EOK) 234 273 goto error; 235 274 236 275 code->ranges = ranges; 237 276 code->cmds = cmds; 238 277 239 278 return code; 240 279 241 280 error: 242 281 if (cmds) 243 282 free(cmds); 283 244 284 if (ranges) 245 285 free(ranges); 286 246 287 free(code); 247 288 return NULL; … … 250 291 /** Register an answerbox as a receiving end for IRQ notifications. 251 292 * 252 * @param box Receiving answerbox. 253 * @param inr IRQ number. 254 * @param devno Device number. 255 * @param imethod Interface and method to be associated with the 256 * notification. 257 * @param ucode Uspace pointer to top-half pseudocode. 258 * @return EOK on success or a negative error code. 293 * @param box Receiving answerbox. 294 * @param inr IRQ number. 295 * @param devno Device number. 296 * @param imethod Interface and method to be associated with the 297 * notification. 298 * @param ucode Uspace pointer to top-half pseudocode. 299 * 300 * @return EOK on success or a negative error code. 259 301 * 260 302 */ … … 266 308 (sysarg_t) devno 267 309 }; 268 310 269 311 if ((inr < 0) || (inr > last_inr)) 270 312 return ELIMIT; … … 329 371 /** Unregister task from IRQ notification. 330 372 * 331 * @param box Answerbox associated with the notification. 332 * @param inr IRQ number. 333 * @param devno Device number. 334 * @return EOK on success or a negative error code. 373 * @param box Answerbox associated with the notification. 374 * @param inr IRQ number. 375 * @param devno Device number. 376 * 377 * @return EOK on success or a negative error code. 378 * 335 379 */ 336 380 int ipc_irq_unregister(answerbox_t *box, inr_t inr, devno_t devno) … … 340 384 (sysarg_t) devno 341 385 }; 342 386 343 387 if ((inr < 0) || (inr > last_inr)) 344 388 return ELIMIT; … … 436 480 /* Remove from the hash table. */ 437 481 hash_table_remove(&irq_uspace_hash_table, key, 2); 438 482 439 483 /* 440 484 * Release both locks so that we can free the pseudo code. … … 442 486 irq_spinlock_unlock(&box->irq_lock, false); 443 487 irq_spinlock_unlock(&irq_uspace_hash_table_lock, true); 444 488 445 489 code_free(irq->notif_cfg.code); 446 490 free(irq); … … 492 536 493 537 for (size_t i = 0; i < code->cmdcount; i++) { 494 uint32_t dstval;495 496 538 uintptr_t srcarg = code->cmds[i].srcarg; 497 539 uintptr_t dstarg = code->cmds[i].dstarg; 498 540 499 if (srcarg >= IPC_CALL_LEN)500 break;501 502 if (dstarg >= IPC_CALL_LEN)503 break;504 505 541 switch (code->cmds[i].cmd) { 506 542 case CMD_PIO_READ_8: 507 dstval = pio_read_8((ioport8_t *) code->cmds[i].addr); 508 if (dstarg) 509 scratch[dstarg] = dstval; 543 scratch[dstarg] = 544 pio_read_8((ioport8_t *) code->cmds[i].addr); 510 545 break; 511 546 case CMD_PIO_READ_16: 512 dstval = pio_read_16((ioport16_t *) code->cmds[i].addr); 513 if (dstarg) 514 scratch[dstarg] = dstval; 547 scratch[dstarg] = 548 pio_read_16((ioport16_t *) code->cmds[i].addr); 515 549 break; 516 550 case CMD_PIO_READ_32: 517 dstval = pio_read_32((ioport32_t *) code->cmds[i].addr); 518 if (dstarg) 519 scratch[dstarg] = dstval; 551 scratch[dstarg] = 552 pio_read_32((ioport32_t *) code->cmds[i].addr); 520 553 break; 521 554 case CMD_PIO_WRITE_8: … … 532 565 break; 533 566 case CMD_PIO_WRITE_A_8: 534 if (srcarg) { 535 pio_write_8((ioport8_t *) code->cmds[i].addr, 536 (uint8_t) scratch[srcarg]); 537 } 567 pio_write_8((ioport8_t *) code->cmds[i].addr, 568 (uint8_t) scratch[srcarg]); 538 569 break; 539 570 case CMD_PIO_WRITE_A_16: 540 if (srcarg) { 541 pio_write_16((ioport16_t *) code->cmds[i].addr, 542 (uint16_t) scratch[srcarg]); 543 } 571 pio_write_16((ioport16_t *) code->cmds[i].addr, 572 (uint16_t) scratch[srcarg]); 544 573 break; 545 574 case CMD_PIO_WRITE_A_32: 546 if (srcarg) { 547 pio_write_32((ioport32_t *) code->cmds[i].addr, 548 (uint32_t) scratch[srcarg]); 549 } 550 break; 551 case CMD_BTEST: 552 if ((srcarg) && (dstarg)) { 553 dstval = scratch[srcarg] & code->cmds[i].value; 554 scratch[dstarg] = dstval; 555 } 575 pio_write_32((ioport32_t *) code->cmds[i].addr, 576 (uint32_t) scratch[srcarg]); 577 break; 578 case CMD_LOAD: 579 scratch[dstarg] = code->cmds[i].value; 580 break; 581 case CMD_AND: 582 scratch[dstarg] = scratch[srcarg] & 583 code->cmds[i].value; 556 584 break; 557 585 case CMD_PREDICATE: 558 if ( (srcarg) && (!scratch[srcarg])) {586 if (scratch[srcarg] == 0) 559 587 i += code->cmds[i].value; 560 continue; 561 } 588 562 589 break; 563 590 case CMD_ACCEPT: … … 582 609 { 583 610 ASSERT(irq); 584 611 585 612 ASSERT(interrupts_disabled()); 586 613 ASSERT(irq_spinlock_locked(&irq->lock));
Note:
See TracChangeset
for help on using the changeset viewer.