Ignore:
File:
1 edited

Legend:

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

    r0d21b53 r7e752b2  
    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
     
    5152#include <print.h>
    5253#include <symtab.h>
    53 
    54 static struct {
    55         const char *name;
    56         iroutine f;
    57 } exc_table[IVT_ITEMS];
    58 
    59 SPINLOCK_INITIALIZE(exctbl_lock);
     54#include <proc/thread.h>
     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);
    6061
    6162/** Register exception handler
    62  *
    63  * @param n Exception number
    64  * @param name Description
    65  * @param f Exception handler
    66  */
    67 iroutine exc_register(int n, const char *name, iroutine f)
    68 {
     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)
    6977        ASSERT(n < IVT_ITEMS);
    70        
    71         iroutine old;
    72        
    73         spinlock_lock(&exctbl_lock);
    74        
    75         old = exc_table[n].f;
    76         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;
    7784        exc_table[n].name = name;
    78        
    79         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);
    8090       
    8191        return old;
     
    8696 * Called directly from the assembler code.
    8797 * CPU is interrupts_disable()'d.
    88  */
    89 void exc_dispatch(int n, istate_t *istate)
    90 {
     98 *
     99 */
     100NO_TRACE void exc_dispatch(unsigned int n, istate_t *istate)
     101{
     102#if (IVT_ITEMS > 0)
    91103        ASSERT(n < IVT_ITEMS);
    92 
     104#endif
     105       
     106        /* Account user cycles */
     107        if (THREAD) {
     108                irq_spinlock_lock(&THREAD->lock, false);
     109                thread_update_accounting(true);
     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       
    93127#ifdef CONFIG_UDEBUG
    94         if (THREAD) THREAD->udebug.uspace_state = istate;
    95 #endif
    96        
    97         exc_table[n].f(n + IVT_FIRST, istate);
    98 
     128        if (THREAD)
     129                THREAD->udebug.uspace_state = istate;
     130#endif
     131       
     132        exc_table[n].handler(n + IVT_FIRST, istate);
     133       
    99134#ifdef CONFIG_UDEBUG
    100         if (THREAD) THREAD->udebug.uspace_state = NULL;
    101 #endif
    102 
     135        if (THREAD)
     136                THREAD->udebug.uspace_state = NULL;
     137#endif
     138       
    103139        /* This is a safe place to exit exiting thread */
    104         if (THREAD && THREAD->interrupted && istate_from_uspace(istate))
     140        if ((THREAD) && (THREAD->interrupted) && (istate_from_uspace(istate)))
    105141                thread_exit();
    106 }
    107 
    108 /** Default 'null' exception handler */
    109 static void exc_undef(int n, istate_t *istate)
    110 {
    111         fault_if_from_uspace(istate, "Unhandled exception %d.", n);
    112         panic("Unhandled exception %d.", n);
    113 }
    114 
    115 /** Terminate thread and task if exception came from userspace. */
    116 void fault_if_from_uspace(istate_t *istate, char *fmt, ...)
    117 {
    118         task_t *task = TASK;
    119         va_list args;
    120 
     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 */
     152        if (THREAD) {
     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_badtrap(istate, n, "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{
    121173        if (!istate_from_uspace(istate))
    122174                return;
    123 
     175       
    124176        printf("Task %s (%" PRIu64 ") killed due to an exception at "
    125             "program counter %p.\n", task->name, task->taskid,
    126             istate_get_pc(istate));
    127 
     177            "program counter %p.\n", TASK->name, TASK->taskid,
     178            (void *) istate_get_pc(istate));
     179       
    128180        stack_trace_istate(istate);
    129 
     181       
    130182        printf("Kill message: ");
     183       
     184        va_list args;
    131185        va_start(args, fmt);
    132186        vprintf(fmt, args);
    133187        va_end(args);
    134188        printf("\n");
    135 
     189       
    136190        /*
    137191         * Userspace can subscribe for FAULT events to take action
     
    144198                event_notify_3(EVENT_FAULT, LOWER32(TASK->taskid),
    145199                    UPPER32(TASK->taskid), (unative_t) THREAD);
    146 
     200               
    147201#ifdef CONFIG_UDEBUG
    148202                /* Wait for a debugging session. */
     
    150204#endif
    151205        }
    152 
    153         task_kill(task->taskid);
     206       
     207        task_kill(TASK->taskid);
    154208        thread_exit();
    155209}
     
    157211#ifdef CONFIG_KCONSOLE
    158212
    159 /** kconsole cmd - print all exceptions */
    160 static int cmd_exc_print(cmd_arg_t *argv)
    161 {
     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       
    162231#if (IVT_ITEMS > 0)
    163232        unsigned int i;
    164         char *symbol;
    165 
    166         spinlock_lock(&exctbl_lock);
    167 
     233        unsigned int rows;
     234       
     235        irq_spinlock_lock(&exctbl_lock, true);
     236       
    168237#ifdef __32_BITS__
    169         printf("Exc Description          Handler    Symbol\n");
    170         printf("--- -------------------- ---------- --------\n");
    171 #endif
    172 
     238        printf("[exc   ] [description       ] [count   ] [cycles  ]"
     239            " [handler ] [symbol\n");
     240        rows = 1;
     241#endif
     242       
    173243#ifdef __64_BITS__
    174         printf("Exc Description          Handler            Symbol\n");
    175         printf("--- -------------------- ------------------ --------\n");
     244        printf("[exc   ] [description       ] [count   ] [cycles  ]"
     245            " [handler         ]\n");
     246        printf("         [symbol\n");
     247        rows = 2;
    176248#endif
    177249       
    178250        for (i = 0; i < IVT_ITEMS; i++) {
    179                 symbol = symtab_fmt_name_lookup((unative_t) exc_table[i].f);
    180 
     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               
    181267#ifdef __32_BITS__
    182                 printf("%-3u %-20s %10p %s\n", i + IVT_FIRST, exc_table[i].name,
    183                         exc_table[i].f, symbol);
    184 #endif
    185 
     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               
    186276#ifdef __64_BITS__
    187                 printf("%-3u %-20s %18p %s\n", i + IVT_FIRST, exc_table[i].name,
    188                         exc_table[i].f, symbol);
    189 #endif
    190                
    191                 if (((i + 1) % 20) == 0) {
    192                         printf(" -- Press any key to continue -- ");
    193                         spinlock_unlock(&exctbl_lock);
    194                         indev_pop_character(stdin);
    195                         spinlock_lock(&exctbl_lock);
    196                         printf("\n");
    197                 }
    198         }
    199        
    200         spinlock_unlock(&exctbl_lock);
    201 #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) */
    202293       
    203294        return 1;
    204295}
    205296
     297static cmd_arg_t exc_argv = {
     298        .type = ARG_TYPE_STRING_OPTIONAL,
     299        .buffer = flag_buf,
     300        .len = sizeof(flag_buf)
     301};
    206302
    207303static cmd_info_t exc_info = {
    208304        .name = "exc",
    209         .description = "Print exception table.",
     305        .description = "Print exception table (use -a for all exceptions).",
    210306        .func = cmd_exc_print,
    211307        .help = NULL,
    212         .argc = 0,
    213         .argv = NULL
     308        .argc = 1,
     309        .argv = &exc_argv
    214310};
    215311
    216 #endif
    217 
    218 /** Initialize generic exception handling support */
     312#endif /* CONFIG_KCONSOLE */
     313
     314/** Initialize generic exception handling support
     315 *
     316 */
    219317void exc_init(void)
    220318{
    221         int i;
    222 
     319        (void) exc_undef;
     320       
     321#if (IVT_ITEMS > 0)
     322        unsigned int i;
     323       
    223324        for (i = 0; i < IVT_ITEMS; i++)
    224                 exc_register(i, "undef", (iroutine) exc_undef);
    225 
     325                exc_register(i, "undef", false, (iroutine_t) exc_undef);
     326#endif
     327       
    226328#ifdef CONFIG_KCONSOLE
    227329        cmd_initialize(&exc_info);
Note: See TracChangeset for help on using the changeset viewer.