Ignore:
File:
1 edited

Legend:

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

    r3cc070d r55b77d9  
    4242 *
    4343 * The structure of a notification message is as follows:
    44  * - IMETHOD: interface and method as registered by
    45  *            the SYS_IRQ_REGISTER syscall
     44 * - IMETHOD: interface and method as registered by the SYS_REGISTER_IRQ
     45 *            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>
    7876#include <errno.h>
    7977#include <ddi/irq.h>
     
    8381#include <console/console.h>
    8482#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 }
    18283
    18384/** Free the top-half pseudocode.
     
    18990{
    19091        if (code) {
    191                 ranges_unmap(code->ranges, code->rangecount);
    192                 free(code->ranges);
    19392                free(code->cmds);
    19493                free(code);
     
    205104static irq_code_t *code_from_uspace(irq_code_t *ucode)
    206105{
    207         irq_pio_range_t *ranges = NULL;
    208         irq_cmd_t *cmds = NULL;
    209 
    210106        irq_code_t *code = malloc(sizeof(*code), 0);
    211107        int rc = copy_from_uspace(code, ucode, sizeof(*code));
    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,
     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,
    227121            sizeof(code->cmds[0]) * code->cmdcount);
    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 
     122        if (rc != 0) {
     123                free(code->cmds);
     124                free(code);
     125                return NULL;
     126        }
     127       
    239128        return code;
    240 
    241 error:
    242         if (cmds)
    243                 free(cmds);
    244         if (ranges)
    245                 free(ranges);
    246         free(code);
    247         return NULL;
    248129}
    249130
     
    293174        irq->notif_cfg.code = code;
    294175        irq->notif_cfg.counter = 0;
     176        irq->driver_as = AS;
    295177       
    296178        /*
     
    357239       
    358240        ASSERT(irq->notif_cfg.answerbox == box);
     241       
     242        /* Free up the pseudo code and associated structures. */
     243        code_free(irq->notif_cfg.code);
    359244       
    360245        /* Remove the IRQ from the answerbox's list. */
     
    375260        irq_spinlock_unlock(&box->irq_lock, false);
    376261        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);
    380262       
    381263        /* Free up the IRQ structure. */
     
    425307                list_remove(&irq->notif_cfg.link);
    426308               
     309                /* Free up the pseudo code and associated structures. */
     310                code_free(irq->notif_cfg.code);
     311               
    427312                /*
    428313                 * We need to drop the IRQ lock now because hash_table_remove()
     
    436321                /* Remove from the hash table. */
    437322                hash_table_remove(&irq_uspace_hash_table, key, 2);
    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);
     323               
    446324                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);
    451325        }
    452326       
     
    491365                return IRQ_DECLINE;
    492366       
    493         for (size_t i = 0; i < code->cmdcount; i++) {
     367#define CMD_MEM_READ(target) \
     368do { \
     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) \
     378do { \
     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++) {
    494388                uint32_t dstval;
    495                
    496389                uintptr_t srcarg = code->cmds[i].srcarg;
    497390                uintptr_t dstarg = code->cmds[i].dstarg;
     
    549442                        }
    550443                        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;
    551492                case CMD_BTEST:
    552493                        if ((srcarg) && (dstarg)) {
     
    562503                        break;
    563504                case CMD_ACCEPT:
     505                        if (AS != current_as)
     506                                as_switch(AS, current_as);
    564507                        return IRQ_ACCEPT;
    565508                case CMD_DECLINE:
    566509                default:
     510                        if (AS != current_as)
     511                                as_switch(AS, current_as);
    567512                        return IRQ_DECLINE;
    568513                }
    569514        }
     515        if (AS != current_as)
     516                as_switch(AS, current_as);
    570517       
    571518        return IRQ_DECLINE;
Note: See TracChangeset for help on using the changeset viewer.