Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • kernel/generic/src/interrupt/interrupt.c

    rcd98e594 r04e3d9f  
    3232/**
    3333 * @file
    34  * @brief       Interrupt redirector.
     34 * @brief Interrupt redirector.
    3535 *
    3636 * This file provides means of registering interrupt handlers
    3737 * by kernel functions and calling the handlers when interrupts
    3838 * occur.
     39 *
    3940 */
    4041
     
    5253#include <symtab.h>
    5354#include <proc/thread.h>
    54 
    55 static struct {
    56         const char *name;
    57         iroutine f;
    58 } exc_table[IVT_ITEMS];
    59 
    60 SPINLOCK_INITIALIZE(exctbl_lock);
     55#include <arch/cycle.h>
     56#include <str.h>
     57#include <trace.h>
     58
     59exc_table_t exc_table[IVT_ITEMS];
     60IRQ_SPINLOCK_INITIALIZE(exctbl_lock);
    6161
    6262/** Register exception handler
    63  *
    64  * @param n Exception number
    65  * @param name Description
    66  * @param f Exception handler
    67  */
    68 iroutine exc_register(int n, const char *name, iroutine f)
    69 {
     63 *
     64 * @param n       Exception number.
     65 * @param name    Description.
     66 * @param hot     Whether the exception is actually handled
     67 *                in any meaningful way.
     68 * @param handler New exception handler.
     69 *
     70 * @return Previously registered exception handler.
     71 *
     72 */
     73iroutine_t exc_register(unsigned int n, const char *name, bool hot,
     74    iroutine_t handler)
     75{
     76#if (IVT_ITEMS > 0)
    7077        ASSERT(n < IVT_ITEMS);
    71        
    72         iroutine old;
    73        
    74         spinlock_lock(&exctbl_lock);
    75        
    76         old = exc_table[n].f;
    77         exc_table[n].f = f;
     78#endif
     79       
     80        irq_spinlock_lock(&exctbl_lock, true);
     81       
     82        iroutine_t old = exc_table[n].handler;
     83        exc_table[n].handler = handler;
    7884        exc_table[n].name = name;
    79        
    80         spinlock_unlock(&exctbl_lock);
     85        exc_table[n].hot = hot;
     86        exc_table[n].cycles = 0;
     87        exc_table[n].count = 0;
     88       
     89        irq_spinlock_unlock(&exctbl_lock, true);
    8190       
    8291        return old;
     
    8796 * Called directly from the assembler code.
    8897 * CPU is interrupts_disable()'d.
    89  */
    90 void exc_dispatch(int n, istate_t *istate)
    91 {
     98 *
     99 */
     100NO_TRACE void exc_dispatch(unsigned int n, istate_t *istate)
     101{
     102#if (IVT_ITEMS > 0)
    92103        ASSERT(n < IVT_ITEMS);
    93 
     104#endif
     105       
    94106        /* Account user cycles */
    95107        if (THREAD) {
    96                 spinlock_lock(&THREAD->lock);
     108                irq_spinlock_lock(&THREAD->lock, false);
    97109                thread_update_accounting(true);
    98                 spinlock_unlock(&THREAD->lock);
    99         }
    100 
     110                irq_spinlock_unlock(&THREAD->lock, false);
     111        }
     112       
     113        /* Account CPU usage if it has waked up from sleep */
     114        if (CPU) {
     115                irq_spinlock_lock(&CPU->lock, false);
     116                if (CPU->idle) {
     117                        uint64_t now = get_cycle();
     118                        CPU->idle_cycles += now - CPU->last_cycle;
     119                        CPU->last_cycle = now;
     120                        CPU->idle = false;
     121                }
     122                irq_spinlock_unlock(&CPU->lock, false);
     123        }
     124       
     125        uint64_t begin_cycle = get_cycle();
     126       
    101127#ifdef CONFIG_UDEBUG
    102         if (THREAD) THREAD->udebug.uspace_state = istate;
    103 #endif
    104        
    105         exc_table[n].f(n + IVT_FIRST, istate);
    106 
     128        if (THREAD)
     129                THREAD->udebug.uspace_state = istate;
     130#endif
     131       
     132        exc_table[n].handler(n + IVT_FIRST, istate);
     133       
    107134#ifdef CONFIG_UDEBUG
    108         if (THREAD) THREAD->udebug.uspace_state = NULL;
    109 #endif
    110 
     135        if (THREAD)
     136                THREAD->udebug.uspace_state = NULL;
     137#endif
     138       
    111139        /* This is a safe place to exit exiting thread */
    112         if (THREAD && THREAD->interrupted && istate_from_uspace(istate))
     140        if ((THREAD) && (THREAD->interrupted) && (istate_from_uspace(istate)))
    113141                thread_exit();
    114 
     142       
     143        /* Account exception handling */
     144        uint64_t end_cycle = get_cycle();
     145       
     146        irq_spinlock_lock(&exctbl_lock, false);
     147        exc_table[n].cycles += end_cycle - begin_cycle;
     148        exc_table[n].count++;
     149        irq_spinlock_unlock(&exctbl_lock, false);
     150       
     151        /* Do not charge THREAD for exception cycles */
    115152        if (THREAD) {
    116                 spinlock_lock(&THREAD->lock);
    117                 thread_update_accounting(false);
    118                 spinlock_unlock(&THREAD->lock);
    119         }
    120 }
    121 
    122 /** Default 'null' exception handler */
    123 static void exc_undef(int n, istate_t *istate)
    124 {
    125         fault_if_from_uspace(istate, "Unhandled exception %d.", n);
    126         panic("Unhandled exception %d.", n);
    127 }
    128 
    129 /** Terminate thread and task if exception came from userspace. */
    130 void fault_if_from_uspace(istate_t *istate, const char *fmt, ...)
    131 {
    132         task_t *task = TASK;
    133         va_list args;
    134 
     153                irq_spinlock_lock(&THREAD->lock, false);
     154                THREAD->last_cycle = end_cycle;
     155                irq_spinlock_unlock(&THREAD->lock, false);
     156        }
     157}
     158
     159/** Default 'null' exception handler
     160 *
     161 */
     162NO_TRACE static void exc_undef(unsigned int n, istate_t *istate)
     163{
     164        fault_if_from_uspace(istate, "Unhandled exception %u.", n);
     165        panic("Unhandled exception %u.", n);
     166}
     167
     168/** Terminate thread and task if exception came from userspace.
     169 *
     170 */
     171NO_TRACE void fault_if_from_uspace(istate_t *istate, const char *fmt, ...)
     172{
    135173        if (!istate_from_uspace(istate))
    136174                return;
    137 
     175       
    138176        printf("Task %s (%" PRIu64 ") killed due to an exception at "
    139             "program counter %p.\n", task->name, task->taskid,
     177            "program counter %p.\n", TASK->name, TASK->taskid,
    140178            istate_get_pc(istate));
    141 
     179       
    142180        stack_trace_istate(istate);
    143 
     181       
    144182        printf("Kill message: ");
     183       
     184        va_list args;
    145185        va_start(args, fmt);
    146186        vprintf(fmt, args);
    147187        va_end(args);
    148188        printf("\n");
    149 
     189       
    150190        /*
    151191         * Userspace can subscribe for FAULT events to take action
     
    158198                event_notify_3(EVENT_FAULT, LOWER32(TASK->taskid),
    159199                    UPPER32(TASK->taskid), (unative_t) THREAD);
    160 
     200               
    161201#ifdef CONFIG_UDEBUG
    162202                /* Wait for a debugging session. */
     
    164204#endif
    165205        }
    166 
    167         task_kill(task->taskid);
     206       
     207        task_kill(TASK->taskid);
    168208        thread_exit();
    169209}
     
    171211#ifdef CONFIG_KCONSOLE
    172212
    173 /** kconsole cmd - print all exceptions */
    174 static int cmd_exc_print(cmd_arg_t *argv)
    175 {
     213static char flag_buf[MAX_CMDLINE + 1];
     214
     215/** Print all exceptions
     216 *
     217 */
     218NO_TRACE static int cmd_exc_print(cmd_arg_t *argv)
     219{
     220        bool excs_all;
     221       
     222        if (str_cmp(flag_buf, "-a") == 0)
     223                excs_all = true;
     224        else if (str_cmp(flag_buf, "") == 0)
     225                excs_all = false;
     226        else {
     227                printf("Unknown argument \"%s\".\n", flag_buf);
     228                return 1;
     229        }
     230       
    176231#if (IVT_ITEMS > 0)
    177232        unsigned int i;
    178 
    179         spinlock_lock(&exctbl_lock);
    180 
     233        unsigned int rows;
     234       
     235        irq_spinlock_lock(&exctbl_lock, true);
     236       
    181237#ifdef __32_BITS__
    182         printf("Exc Description          Handler    Symbol\n");
    183         printf("--- -------------------- ---------- --------\n");
    184 #endif
    185 
     238        printf("[exc   ] [description       ] [count   ] [cycles  ]"
     239            " [handler ] [symbol\n");
     240        rows = 1;
     241#endif
     242       
    186243#ifdef __64_BITS__
    187         printf("Exc Description          Handler            Symbol\n");
    188         printf("--- -------------------- ------------------ --------\n");
     244        printf("[exc   ] [description       ] [count   ] [cycles  ]"
     245            " [handler         ]\n");
     246        printf("         [symbol\n");
     247        rows = 2;
    189248#endif
    190249       
    191250        for (i = 0; i < IVT_ITEMS; i++) {
    192                 const char *symbol = symtab_fmt_name_lookup((unative_t) exc_table[i].f);
    193 
     251                if ((!excs_all) && (!exc_table[i].hot))
     252                        continue;
     253               
     254                uint64_t count;
     255                char count_suffix;
     256               
     257                order_suffix(exc_table[i].count, &count, &count_suffix);
     258               
     259                uint64_t cycles;
     260                char cycles_suffix;
     261               
     262                order_suffix(exc_table[i].cycles, &cycles, &cycles_suffix);
     263               
     264                const char *symbol =
     265                    symtab_fmt_name_lookup((unative_t) exc_table[i].handler);
     266               
    194267#ifdef __32_BITS__
    195                 printf("%-3u %-20s %10p %s\n", i + IVT_FIRST, exc_table[i].name,
    196                         exc_table[i].f, symbol);
    197 #endif
    198 
     268                printf("%-8u %-20s %9" PRIu64 "%c %9" PRIu64 "%c %10p %s\n",
     269                    i + IVT_FIRST, exc_table[i].name, count, count_suffix,
     270                    cycles, cycles_suffix, exc_table[i].handler, symbol);
     271               
     272                PAGING(rows, 1, irq_spinlock_unlock(&exctbl_lock, true),
     273                    irq_spinlock_lock(&exctbl_lock, true));
     274#endif
     275               
    199276#ifdef __64_BITS__
    200                 printf("%-3u %-20s %18p %s\n", i + IVT_FIRST, exc_table[i].name,
    201                         exc_table[i].f, symbol);
    202 #endif
    203                
    204                 if (((i + 1) % 20) == 0) {
    205                         printf(" -- Press any key to continue -- ");
    206                         spinlock_unlock(&exctbl_lock);
    207                         indev_pop_character(stdin);
    208                         spinlock_lock(&exctbl_lock);
    209                         printf("\n");
    210                 }
    211         }
    212        
    213         spinlock_unlock(&exctbl_lock);
    214 #endif
     277                printf("%-8u %-20s %9" PRIu64 "%c %9" PRIu64 "%c %18p\n",
     278                    i + IVT_FIRST, exc_table[i].name, count, count_suffix,
     279                    cycles, cycles_suffix, exc_table[i].handler);
     280                printf("         %s\n", symbol);
     281               
     282                PAGING(rows, 2, irq_spinlock_unlock(&exctbl_lock, true),
     283                    irq_spinlock_lock(&exctbl_lock, true));
     284#endif
     285        }
     286       
     287        irq_spinlock_unlock(&exctbl_lock, true);
     288#else /* (IVT_ITEMS > 0) */
     289       
     290        printf("No exception table%s.\n", excs_all ? " (showing all exceptions)" : "");
     291       
     292#endif /* (IVT_ITEMS > 0) */
    215293       
    216294        return 1;
    217295}
    218296
     297static cmd_arg_t exc_argv = {
     298        .type = ARG_TYPE_STRING_OPTIONAL,
     299        .buffer = flag_buf,
     300        .len = sizeof(flag_buf)
     301};
    219302
    220303static cmd_info_t exc_info = {
    221304        .name = "exc",
    222         .description = "Print exception table.",
     305        .description = "Print exception table (use -a for all exceptions).",
    223306        .func = cmd_exc_print,
    224307        .help = NULL,
    225         .argc = 0,
    226         .argv = NULL
     308        .argc = 1,
     309        .argv = &exc_argv
    227310};
    228311
    229 #endif
    230 
    231 /** Initialize generic exception handling support */
     312#endif /* CONFIG_KCONSOLE */
     313
     314/** Initialize generic exception handling support
     315 *
     316 */
    232317void exc_init(void)
    233318{
    234         int i;
    235 
     319        (void) exc_undef;
     320       
     321#if (IVT_ITEMS > 0)
     322        unsigned int i;
     323       
    236324        for (i = 0; i < IVT_ITEMS; i++)
    237                 exc_register(i, "undef", (iroutine) exc_undef);
    238 
     325                exc_register(i, "undef", false, (iroutine_t) exc_undef);
     326#endif
     327       
    239328#ifdef CONFIG_KCONSOLE
    240329        cmd_initialize(&exc_info);
Note: See TracChangeset for help on using the changeset viewer.