Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • kernel/generic/src/ipc/irq.c

    r8486c07 r9d58539  
    3939 * when interrupt is detected. The application may provide a simple 'top-half'
    4040 * handler as part of its registration, which can perform simple operations
    41  * (read/write port/memory, add information to notification IPC message).
     41 * (read/write port/memory, add information to notification ipc message).
    4242 *
    4343 * The structure of a notification message is as follows:
    4444 * - IMETHOD: interface and method as registered by
    4545 *            the SYS_IRQ_REGISTER syscall
    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])
     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
    5151 * - in_phone_hash: interrupt counter (may be needed to assure correct order
    5252 *                  in multithreaded drivers)
     
    8787static void ranges_unmap(irq_pio_range_t *ranges, size_t rangecount)
    8888{
    89         for (size_t i = 0; i < rangecount; i++) {
     89        size_t i;
     90
     91        for (i = 0; i < rangecount; i++) {
    9092#ifdef IO_SPACE_BOUNDARY
    9193                if ((void *) ranges[i].base >= IO_SPACE_BOUNDARY)
     
    98100    irq_cmd_t *cmds, size_t cmdcount)
    99101{
     102        uintptr_t *pbase;
     103        size_t i, j;
     104
    100105        /* Copy the physical base addresses aside. */
    101         uintptr_t *pbase = malloc(rangecount * sizeof(uintptr_t), 0);
    102         for (size_t i = 0; i < rangecount; i++)
     106        pbase = malloc(rangecount * sizeof(uintptr_t), 0);
     107        for (i = 0; i < rangecount; i++)
    103108                pbase[i] = ranges[i].base;
    104        
     109
    105110        /* Map the PIO ranges into the kernel virtual address space. */
    106         for (size_t i = 0; i < rangecount; i++) {
     111        for (i = 0; i < rangecount; i++) {
    107112#ifdef IO_SPACE_BOUNDARY
    108113                if ((void *) ranges[i].base < IO_SPACE_BOUNDARY)
     
    117122                }
    118123        }
    119        
     124
    120125        /* Rewrite the pseudocode addresses from physical to kernel virtual. */
    121         for (size_t i = 0; i < cmdcount; i++) {
     126        for (i = 0; i < cmdcount; i++) {
    122127                uintptr_t addr;
    123128                size_t size;
    124                
     129
    125130                /* Process only commands that use an address. */
    126131                switch (cmds[i].cmd) {
    127132                case CMD_PIO_READ_8:
    128                 case CMD_PIO_WRITE_8:
    129                 case CMD_PIO_WRITE_A_8:
     133                case CMD_PIO_WRITE_8:
     134                case CMD_PIO_WRITE_A_8:
    130135                        size = 1;
    131136                        break;
    132                 case CMD_PIO_READ_16:
    133                 case CMD_PIO_WRITE_16:
    134                 case CMD_PIO_WRITE_A_16:
     137                case CMD_PIO_READ_16:
     138                case CMD_PIO_WRITE_16:
     139                case CMD_PIO_WRITE_A_16:
    135140                        size = 2;
    136141                        break;
    137                 case CMD_PIO_READ_32:
    138                 case CMD_PIO_WRITE_32:
    139                 case CMD_PIO_WRITE_A_32:
     142                case CMD_PIO_READ_32:
     143                case CMD_PIO_WRITE_32:
     144                case CMD_PIO_WRITE_A_32:
    140145                        size = 4;
    141146                        break;
     
    144149                        continue;
    145150                }
    146                
     151
    147152                addr = (uintptr_t) cmds[i].addr;
    148153               
    149                 size_t j;
    150154                for (j = 0; j < rangecount; j++) {
     155
    151156                        /* Find the matching range. */
    152157                        if (!iswithin(pbase[j], ranges[j].size, addr, size))
    153158                                continue;
    154                        
     159
    155160                        /* Switch the command to a kernel virtual address. */
    156161                        addr -= pbase[j];
    157162                        addr += ranges[j].base;
    158                        
     163
    159164                        cmds[i].addr = (void *) addr;
    160165                        break;
    161166                }
    162                
     167
    163168                if (j == rangecount) {
    164169                        /*
     
    171176                }
    172177        }
    173        
     178
    174179        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        
    215180        return EOK;
    216181}
     
    242207        irq_pio_range_t *ranges = NULL;
    243208        irq_cmd_t *cmds = NULL;
    244        
     209
    245210        irq_code_t *code = malloc(sizeof(*code), 0);
    246211        int rc = copy_from_uspace(code, ucode, sizeof(*code));
     
    257222        if (rc != EOK)
    258223                goto error;
    259        
     224
    260225        cmds = malloc(sizeof(code->cmds[0]) * code->cmdcount, 0);
    261226        rc = copy_from_uspace(cmds, code->cmds,
     
    263228        if (rc != EOK)
    264229                goto error;
    265        
    266         rc = code_check(cmds, code->cmdcount);
    267         if (rc != EOK)
    268                 goto error;
    269        
     230
    270231        rc = ranges_map_and_apply(ranges, code->rangecount, cmds,
    271232            code->cmdcount);
    272233        if (rc != EOK)
    273234                goto error;
    274        
     235
    275236        code->ranges = ranges;
    276237        code->cmds = cmds;
    277        
     238
    278239        return code;
    279        
     240
    280241error:
    281242        if (cmds)
    282243                free(cmds);
    283        
    284244        if (ranges)
    285245                free(ranges);
    286        
    287246        free(code);
    288247        return NULL;
     
    291250/** Register an answerbox as a receiving end for IRQ notifications.
    292251 *
    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.
     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.
    301259 *
    302260 */
     
    308266                (sysarg_t) devno
    309267        };
    310        
     268
    311269        if ((inr < 0) || (inr > last_inr))
    312270                return ELIMIT;
     
    371329/** Unregister task from IRQ notification.
    372330 *
    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  *
     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.
    379335 */
    380336int ipc_irq_unregister(answerbox_t *box, inr_t inr, devno_t devno)
     
    384340                (sysarg_t) devno
    385341        };
    386        
     342
    387343        if ((inr < 0) || (inr > last_inr))
    388344                return ELIMIT;
     
    480436                /* Remove from the hash table. */
    481437                hash_table_remove(&irq_uspace_hash_table, key, 2);
    482                
     438
    483439                /*
    484440                 * Release both locks so that we can free the pseudo code.
     
    486442                irq_spinlock_unlock(&box->irq_lock, false);
    487443                irq_spinlock_unlock(&irq_uspace_hash_table_lock, true);
    488                
     444
    489445                code_free(irq->notif_cfg.code);
    490446                free(irq);
     
    536492       
    537493        for (size_t i = 0; i < code->cmdcount; i++) {
     494                uint32_t dstval;
     495               
    538496                uintptr_t srcarg = code->cmds[i].srcarg;
    539497                uintptr_t dstarg = code->cmds[i].dstarg;
    540498               
     499                if (srcarg >= IPC_CALL_LEN)
     500                        break;
     501               
     502                if (dstarg >= IPC_CALL_LEN)
     503                        break;
     504       
    541505                switch (code->cmds[i].cmd) {
    542506                case CMD_PIO_READ_8:
    543                         scratch[dstarg] =
    544                             pio_read_8((ioport8_t *) code->cmds[i].addr);
     507                        dstval = pio_read_8((ioport8_t *) code->cmds[i].addr);
     508                        if (dstarg)
     509                                scratch[dstarg] = dstval;
    545510                        break;
    546511                case CMD_PIO_READ_16:
    547                         scratch[dstarg] =
    548                             pio_read_16((ioport16_t *) code->cmds[i].addr);
     512                        dstval = pio_read_16((ioport16_t *) code->cmds[i].addr);
     513                        if (dstarg)
     514                                scratch[dstarg] = dstval;
    549515                        break;
    550516                case CMD_PIO_READ_32:
    551                         scratch[dstarg] =
    552                             pio_read_32((ioport32_t *) code->cmds[i].addr);
     517                        dstval = pio_read_32((ioport32_t *) code->cmds[i].addr);
     518                        if (dstarg)
     519                                scratch[dstarg] = dstval;
    553520                        break;
    554521                case CMD_PIO_WRITE_8:
     
    565532                        break;
    566533                case CMD_PIO_WRITE_A_8:
    567                         pio_write_8((ioport8_t *) code->cmds[i].addr,
    568                             (uint8_t) scratch[srcarg]);
     534                        if (srcarg) {
     535                                pio_write_8((ioport8_t *) code->cmds[i].addr,
     536                                    (uint8_t) scratch[srcarg]);
     537                        }
    569538                        break;
    570539                case CMD_PIO_WRITE_A_16:
    571                         pio_write_16((ioport16_t *) code->cmds[i].addr,
    572                             (uint16_t) scratch[srcarg]);
     540                        if (srcarg) {
     541                                pio_write_16((ioport16_t *) code->cmds[i].addr,
     542                                    (uint16_t) scratch[srcarg]);
     543                        }
    573544                        break;
    574545                case CMD_PIO_WRITE_A_32:
    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;
     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                        }
    584556                        break;
    585557                case CMD_PREDICATE:
    586                         if (scratch[srcarg] == 0)
     558                        if ((srcarg) && (!scratch[srcarg])) {
    587559                                i += code->cmds[i].value;
    588                        
     560                                continue;
     561                        }
    589562                        break;
    590563                case CMD_ACCEPT:
     
    609582{
    610583        ASSERT(irq);
    611        
     584
    612585        ASSERT(interrupts_disabled());
    613586        ASSERT(irq_spinlock_locked(&irq->lock));
Note: See TracChangeset for help on using the changeset viewer.