Ignore:
File:
1 edited

Legend:

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

    r3cc070d r17b3cc6  
    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       
     367        as_t *current_as = AS;
     368        if (current_as != irq->driver_as)
     369                as_switch(AS, irq->driver_as);
     370       
    493371        for (size_t i = 0; i < code->cmdcount; i++) {
    494372                uint32_t dstval;
     373                void *va;
     374                uint8_t val8;
     375                uint16_t val16;
     376                uint32_t val32;
    495377               
    496378                uintptr_t srcarg = code->cmds[i].srcarg;
     
    549431                        }
    550432                        break;
     433                case CMD_MEM_READ_8:
     434                        va = code->cmds[i].addr;
     435                        memcpy_from_uspace(&val8, va, sizeof(val8));
     436                        if (dstarg)
     437                                scratch[dstarg] = val8;
     438                        break;
     439                case CMD_MEM_READ_16:
     440                        va = code->cmds[i].addr;
     441                        memcpy_from_uspace(&val16, va, sizeof(val16));
     442                        if (dstarg)
     443                                scratch[dstarg] = val16;
     444                        break;
     445                case CMD_MEM_READ_32:
     446                        va = code->cmds[i].addr;
     447                        memcpy_from_uspace(&val32, va, sizeof(val32));
     448                        if (dstarg)
     449                                scratch[dstarg] = val32;
     450                        break;
     451                case CMD_MEM_WRITE_8:
     452                        val8 = code->cmds[i].value;
     453                        va = code->cmds[i].addr;
     454                        memcpy_to_uspace(va, &val8, sizeof(val8));
     455                        break;
     456                case CMD_MEM_WRITE_16:
     457                        val16 = code->cmds[i].value;
     458                        va = code->cmds[i].addr;
     459                        memcpy_to_uspace(va, &val16, sizeof(val16));
     460                        break;
     461                case CMD_MEM_WRITE_32:
     462                        val32 = code->cmds[i].value;
     463                        va = code->cmds[i].addr;
     464                        memcpy_to_uspace(va, &val32, sizeof(val32));
     465                        break;
     466                case CMD_MEM_WRITE_A_8:
     467                        if (srcarg) {
     468                                val8 = scratch[srcarg];
     469                                va = code->cmds[i].addr;
     470                                memcpy_to_uspace(va, &val8, sizeof(val8));
     471                        }
     472                        break;
     473                case CMD_MEM_WRITE_A_16:
     474                        if (srcarg) {
     475                                val16 = scratch[srcarg];
     476                                va = code->cmds[i].addr;
     477                                memcpy_to_uspace(va, &val16, sizeof(val16));
     478                        }
     479                        break;
     480                case CMD_MEM_WRITE_A_32:
     481                        if (srcarg) {
     482                                val32 = scratch[srcarg];
     483                                va = code->cmds[i].addr;
     484                                memcpy_to_uspace(va, &val32, sizeof(val32));
     485                        }
     486                        break;
    551487                case CMD_BTEST:
    552488                        if ((srcarg) && (dstarg)) {
     
    562498                        break;
    563499                case CMD_ACCEPT:
     500                        if (AS != current_as)
     501                                as_switch(AS, current_as);
    564502                        return IRQ_ACCEPT;
    565503                case CMD_DECLINE:
    566504                default:
     505                        if (AS != current_as)
     506                                as_switch(AS, current_as);
    567507                        return IRQ_DECLINE;
    568508                }
    569509        }
     510       
     511        if (AS != current_as)
     512                as_switch(AS, current_as);
    570513       
    571514        return IRQ_DECLINE;
Note: See TracChangeset for help on using the changeset viewer.