Ignore:
File:
1 edited

Legend:

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

    r44b7783 r5bcf1f9  
    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
     
    4445#include <console/console.h>
    4546#include <console/cmd.h>
     47#include <synch/mutex.h>
     48#include <time/delay.h>
     49#include <macros.h>
    4650#include <panic.h>
    4751#include <print.h>
    4852#include <symtab.h>
    49 
    50 static struct {
    51         const char *name;
    52         iroutine f;
    53 } exc_table[IVT_ITEMS];
    54 
    55 SPINLOCK_INITIALIZE(exctbl_lock);
     53#include <proc/thread.h>
     54#include <arch/cycle.h>
     55#include <str.h>
     56#include <trace.h>
     57
     58exc_table_t exc_table[IVT_ITEMS];
     59IRQ_SPINLOCK_INITIALIZE(exctbl_lock);
    5660
    5761/** Register exception handler
    58  *
    59  * @param n Exception number
    60  * @param name Description
    61  * @param f Exception handler
    62  */
    63 iroutine exc_register(int n, const char *name, iroutine f)
    64 {
     62 *
     63 * @param n       Exception number.
     64 * @param name    Description.
     65 * @param hot     Whether the exception is actually handled
     66 *                in any meaningful way.
     67 * @param handler New exception handler.
     68 *
     69 * @return Previously registered exception handler.
     70 *
     71 */
     72iroutine_t exc_register(unsigned int n, const char *name, bool hot,
     73    iroutine_t handler)
     74{
     75#if (IVT_ITEMS > 0)
    6576        ASSERT(n < IVT_ITEMS);
    66        
    67         iroutine old;
    68        
    69         spinlock_lock(&exctbl_lock);
    70        
    71         old = exc_table[n].f;
    72         exc_table[n].f = f;
     77#endif
     78       
     79        irq_spinlock_lock(&exctbl_lock, true);
     80       
     81        iroutine_t old = exc_table[n].handler;
     82        exc_table[n].handler = handler;
    7383        exc_table[n].name = name;
    74        
    75         spinlock_unlock(&exctbl_lock);
     84        exc_table[n].hot = hot;
     85        exc_table[n].cycles = 0;
     86        exc_table[n].count = 0;
     87       
     88        irq_spinlock_unlock(&exctbl_lock, true);
    7689       
    7790        return old;
     
    8295 * Called directly from the assembler code.
    8396 * CPU is interrupts_disable()'d.
    84  */
    85 void exc_dispatch(int n, istate_t *istate)
    86 {
     97 *
     98 */
     99NO_TRACE void exc_dispatch(unsigned int n, istate_t *istate)
     100{
     101#if (IVT_ITEMS > 0)
    87102        ASSERT(n < IVT_ITEMS);
    88 
     103#endif
     104       
     105        /* Account user cycles */
     106        if (THREAD) {
     107                irq_spinlock_lock(&THREAD->lock, false);
     108                thread_update_accounting(true);
     109                irq_spinlock_unlock(&THREAD->lock, false);
     110        }
     111       
     112        /* Account CPU usage if it has waked up from sleep */
     113        if (CPU) {
     114                irq_spinlock_lock(&CPU->lock, false);
     115                if (CPU->idle) {
     116                        uint64_t now = get_cycle();
     117                        CPU->idle_cycles += now - CPU->last_cycle;
     118                        CPU->last_cycle = now;
     119                        CPU->idle = false;
     120                }
     121                irq_spinlock_unlock(&CPU->lock, false);
     122        }
     123       
     124        uint64_t begin_cycle = get_cycle();
     125       
    89126#ifdef CONFIG_UDEBUG
    90         if (THREAD) THREAD->udebug.uspace_state = istate;
    91 #endif
    92        
    93         exc_table[n].f(n + IVT_FIRST, istate);
    94 
     127        if (THREAD)
     128                THREAD->udebug.uspace_state = istate;
     129#endif
     130       
     131        exc_table[n].handler(n + IVT_FIRST, istate);
     132       
    95133#ifdef CONFIG_UDEBUG
    96         if (THREAD) THREAD->udebug.uspace_state = NULL;
    97 #endif
    98 
     134        if (THREAD)
     135                THREAD->udebug.uspace_state = NULL;
     136#endif
     137       
    99138        /* This is a safe place to exit exiting thread */
    100         if (THREAD && THREAD->interrupted && istate_from_uspace(istate))
     139        if ((THREAD) && (THREAD->interrupted) && (istate_from_uspace(istate)))
    101140                thread_exit();
    102 }
    103 
    104 /** Default 'null' exception handler */
    105 static void exc_undef(int n, istate_t *istate)
    106 {
    107         fault_if_from_uspace(istate, "Unhandled exception %d.", n);
    108         panic("Unhandled exception %d.", n);
     141       
     142        /* Account exception handling */
     143        uint64_t end_cycle = get_cycle();
     144       
     145        irq_spinlock_lock(&exctbl_lock, false);
     146        exc_table[n].cycles += end_cycle - begin_cycle;
     147        exc_table[n].count++;
     148        irq_spinlock_unlock(&exctbl_lock, false);
     149       
     150        /* Do not charge THREAD for exception cycles */
     151        if (THREAD) {
     152                irq_spinlock_lock(&THREAD->lock, false);
     153                THREAD->last_cycle = end_cycle;
     154                irq_spinlock_unlock(&THREAD->lock, false);
     155        }
     156}
     157
     158/** Default 'null' exception handler
     159 *
     160 */
     161NO_TRACE static void exc_undef(unsigned int n, istate_t *istate)
     162{
     163        fault_if_from_uspace(istate, "Unhandled exception %u.", n);
     164        panic_badtrap(istate, n, "Unhandled exception %u.", n);
     165}
     166
     167/** Terminate thread and task if exception came from userspace.
     168 *
     169 */
     170NO_TRACE void fault_if_from_uspace(istate_t *istate, const char *fmt, ...)
     171{
     172        if (!istate_from_uspace(istate))
     173                return;
     174       
     175        printf("Task %s (%" PRIu64 ") killed due to an exception at "
     176            "program counter %p.\n", TASK->name, TASK->taskid,
     177            (void *) istate_get_pc(istate));
     178       
     179        stack_trace_istate(istate);
     180       
     181        printf("Kill message: ");
     182       
     183        va_list args;
     184        va_start(args, fmt);
     185        vprintf(fmt, args);
     186        va_end(args);
     187        printf("\n");
     188       
     189        task_kill_self(true);
     190}
     191
     192/** Get istate structure of a thread.
     193 *
     194 * Get pointer to the istate structure at the bottom of the kernel stack.
     195 *
     196 * This function can be called in interrupt or user context. In interrupt
     197 * context the istate structure is created by the low-level exception
     198 * handler. In user context the istate structure is created by the
     199 * low-level syscall handler.
     200 */
     201istate_t *istate_get(thread_t *thread)
     202{
     203        /*
     204         * The istate structure should be right at the bottom of the kernel
     205         * stack.
     206         */
     207        return (istate_t *) ((uint8_t *) thread->kstack + THREAD_STACK_SIZE -
     208            sizeof(istate_t));
    109209}
    110210
    111211#ifdef CONFIG_KCONSOLE
    112212
    113 /** kconsole cmd - print all exceptions */
    114 static int cmd_exc_print(cmd_arg_t *argv)
    115 {
     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       
    116231#if (IVT_ITEMS > 0)
    117232        unsigned int i;
    118         char *symbol;
    119 
    120         spinlock_lock(&exctbl_lock);
    121 
     233        unsigned int rows;
     234       
     235        irq_spinlock_lock(&exctbl_lock, true);
     236       
    122237#ifdef __32_BITS__
    123         printf("Exc Description          Handler    Symbol\n");
    124         printf("--- -------------------- ---------- --------\n");
    125 #endif
    126 
     238        printf("[exc   ] [description       ] [count   ] [cycles  ]"
     239            " [handler ] [symbol\n");
     240        rows = 1;
     241#endif
     242       
    127243#ifdef __64_BITS__
    128         printf("Exc Description          Handler            Symbol\n");
    129         printf("--- -------------------- ------------------ --------\n");
     244        printf("[exc   ] [description       ] [count   ] [cycles  ]"
     245            " [handler         ]\n");
     246        printf("         [symbol\n");
     247        rows = 2;
    130248#endif
    131249       
    132250        for (i = 0; i < IVT_ITEMS; i++) {
    133                 symbol = symtab_fmt_name_lookup((unative_t) exc_table[i].f);
    134 
     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((sysarg_t) exc_table[i].handler);
     266               
    135267#ifdef __32_BITS__
    136                 printf("%-3u %-20s %10p %s\n", i + IVT_FIRST, exc_table[i].name,
    137                         exc_table[i].f, symbol);
    138 #endif
    139 
     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               
    140276#ifdef __64_BITS__
    141                 printf("%-3u %-20s %18p %s\n", i + IVT_FIRST, exc_table[i].name,
    142                         exc_table[i].f, symbol);
    143 #endif
    144                
    145                 if (((i + 1) % 20) == 0) {
    146                         printf(" -- Press any key to continue -- ");
    147                         spinlock_unlock(&exctbl_lock);
    148                         indev_pop_character(stdin);
    149                         spinlock_lock(&exctbl_lock);
    150                         printf("\n");
    151                 }
    152         }
    153        
    154         spinlock_unlock(&exctbl_lock);
    155 #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) */
    156293       
    157294        return 1;
    158295}
    159296
     297static cmd_arg_t exc_argv = {
     298        .type = ARG_TYPE_STRING_OPTIONAL,
     299        .buffer = flag_buf,
     300        .len = sizeof(flag_buf)
     301};
    160302
    161303static cmd_info_t exc_info = {
    162304        .name = "exc",
    163         .description = "Print exception table.",
     305        .description = "Print exception table (use -a for all exceptions).",
    164306        .func = cmd_exc_print,
    165307        .help = NULL,
    166         .argc = 0,
    167         .argv = NULL
     308        .argc = 1,
     309        .argv = &exc_argv
    168310};
    169311
    170 #endif
    171 
    172 /** Initialize generic exception handling support */
     312#endif /* CONFIG_KCONSOLE */
     313
     314/** Initialize generic exception handling support
     315 *
     316 */
    173317void exc_init(void)
    174318{
    175         int i;
    176 
     319        (void) exc_undef;
     320       
     321#if (IVT_ITEMS > 0)
     322        unsigned int i;
     323       
    177324        for (i = 0; i < IVT_ITEMS; i++)
    178                 exc_register(i, "undef", (iroutine) exc_undef);
    179 
     325                exc_register(i, "undef", false, (iroutine_t) exc_undef);
     326#endif
     327       
    180328#ifdef CONFIG_KCONSOLE
    181329        cmd_initialize(&exc_info);
Note: See TracChangeset for help on using the changeset viewer.