Ignore:
File:
1 edited

Legend:

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

    r55b77d9 r3cc070d  
    4242 *
    4343 * The structure of a notification message is as follows:
    44  * - IMETHOD: interface and method as registered by the SYS_REGISTER_IRQ
    45  *            syscall
     44 * - IMETHOD: interface and method as registered by
     45 *            the SYS_IRQ_REGISTER syscall
    4646 * - ARG1: payload modified by a 'top-half' handler
    4747 * - ARG2: payload modified by a 'top-half' handler
     
    7474#include <arch.h>
    7575#include <mm/slab.h>
     76#include <mm/page.h>
     77#include <mm/km.h>
    7678#include <errno.h>
    7779#include <ddi/irq.h>
     
    8183#include <console/console.h>
    8284#include <print.h>
     85#include <macros.h>
     86
     87static 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
     99static 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}
    83182
    84183/** Free the top-half pseudocode.
     
    90189{
    91190        if (code) {
     191                ranges_unmap(code->ranges, code->rangecount);
     192                free(code->ranges);
    92193                free(code->cmds);
    93194                free(code);
     
    104205static irq_code_t *code_from_uspace(irq_code_t *ucode)
    105206{
     207        irq_pio_range_t *ranges = NULL;
     208        irq_cmd_t *cmds = NULL;
     209
    106210        irq_code_t *code = malloc(sizeof(*code), 0);
    107211        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,
    121227            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
    128239        return code;
     240
     241error:
     242        if (cmds)
     243                free(cmds);
     244        if (ranges)
     245                free(ranges);
     246        free(code);
     247        return NULL;
    129248}
    130249
     
    174293        irq->notif_cfg.code = code;
    175294        irq->notif_cfg.counter = 0;
    176         irq->driver_as = AS;
    177295       
    178296        /*
     
    239357       
    240358        ASSERT(irq->notif_cfg.answerbox == box);
    241        
    242         /* Free up the pseudo code and associated structures. */
    243         code_free(irq->notif_cfg.code);
    244359       
    245360        /* Remove the IRQ from the answerbox's list. */
     
    260375        irq_spinlock_unlock(&box->irq_lock, false);
    261376        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);
    262380       
    263381        /* Free up the IRQ structure. */
     
    307425                list_remove(&irq->notif_cfg.link);
    308426               
    309                 /* Free up the pseudo code and associated structures. */
    310                 code_free(irq->notif_cfg.code);
    311                
    312427                /*
    313428                 * We need to drop the IRQ lock now because hash_table_remove()
     
    321436                /* Remove from the hash table. */
    322437                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);
    324446                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);
    325451        }
    326452       
     
    365491                return IRQ_DECLINE;
    366492       
    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++) {
    388494                uint32_t dstval;
     495               
    389496                uintptr_t srcarg = code->cmds[i].srcarg;
    390497                uintptr_t dstarg = code->cmds[i].dstarg;
     
    442549                        }
    443550                        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;
    492551                case CMD_BTEST:
    493552                        if ((srcarg) && (dstarg)) {
     
    503562                        break;
    504563                case CMD_ACCEPT:
    505                         if (AS != current_as)
    506                                 as_switch(AS, current_as);
    507564                        return IRQ_ACCEPT;
    508565                case CMD_DECLINE:
    509566                default:
    510                         if (AS != current_as)
    511                                 as_switch(AS, current_as);
    512567                        return IRQ_DECLINE;
    513568                }
    514569        }
    515         if (AS != current_as)
    516                 as_switch(AS, current_as);
    517570       
    518571        return IRQ_DECLINE;
Note: See TracChangeset for help on using the changeset viewer.