2 * Copyright (c) 2005 Ondrej Palkovsky
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 /** @addtogroup kernel_generic_interrupt
34 * @brief Interrupt redirector.
36 * This file provides means of registering interrupt handlers
37 * by kernel functions and calling the handlers when interrupts
43 #include <interrupt.h>
44 #include <console/kconsole.h>
45 #include <console/console.h>
46 #include <console/cmd.h>
47 #include <synch/mutex.h>
48 #include <time/delay.h>
54 #include <proc/thread.h>
55 #include <arch/cycle.h>
56 #include <arch/stack.h>
61 * If IVT_ITEMS is zero (e.g. for special/abs32le) we hide completely any
62 * access to the exception table array and panic if the function is called
63 * at all. It also silences (correct) compiler warnings about possible
64 * out-of-bound array access.
67 exc_table_t exc_table
[IVT_ITEMS
];
68 IRQ_SPINLOCK_INITIALIZE(exctbl_lock
);
70 /** Register exception handler
72 * @param n Exception number.
73 * @param name Description.
74 * @param hot Whether the exception is actually handled
75 * in any meaningful way.
76 * @param handler New exception handler.
78 * @return Previously registered exception handler.
81 iroutine_t
exc_register(unsigned int n
, const char *name
, bool hot
,
85 assert(n
< IVT_ITEMS
);
87 irq_spinlock_lock(&exctbl_lock
, true);
89 iroutine_t old
= exc_table
[n
].handler
;
90 exc_table
[n
].handler
= handler
;
91 exc_table
[n
].name
= name
;
92 exc_table
[n
].hot
= hot
;
93 exc_table
[n
].cycles
= 0;
94 exc_table
[n
].count
= 0;
96 irq_spinlock_unlock(&exctbl_lock
, true);
100 panic("No space for any exception handler, cannot register.");
104 /** Dispatch exception according to exception table
106 * Called directly from the assembler code.
107 * CPU is interrupts_disable()'d.
110 _NO_TRACE
void exc_dispatch(unsigned int n
, istate_t
*istate
)
113 assert(n
< IVT_ITEMS
);
115 /* Account user cycles */
117 thread_update_accounting(true);
119 /* Account CPU usage if it woke up from sleep */
120 if (CPU
&& CPU_LOCAL
->idle
) {
121 uint64_t now
= get_cycle();
122 atomic_time_increment(&CPU
->idle_cycles
, now
- CPU_LOCAL
->last_cycle
);
123 CPU_LOCAL
->last_cycle
= now
;
124 CPU_LOCAL
->idle
= false;
127 uint64_t begin_cycle
= get_cycle();
131 THREAD
->udebug
.uspace_state
= istate
;
134 exc_table
[n
].handler(n
+ IVT_FIRST
, istate
);
138 THREAD
->udebug
.uspace_state
= NULL
;
141 /* This is a safe place to exit exiting thread */
142 if ((THREAD
) && (THREAD
->interrupted
) && (istate_from_uspace(istate
)))
145 /* Account exception handling */
146 uint64_t end_cycle
= get_cycle();
148 irq_spinlock_lock(&exctbl_lock
, false);
149 exc_table
[n
].cycles
+= end_cycle
- begin_cycle
;
150 exc_table
[n
].count
++;
151 irq_spinlock_unlock(&exctbl_lock
, false);
153 /* Do not charge THREAD for exception cycles */
155 THREAD
->last_cycle
= end_cycle
;
157 panic("No space for any exception handler, yet we want to handle some exception.");
161 /** Default 'null' exception handler
164 _NO_TRACE
static void exc_undef(unsigned int n
, istate_t
*istate
)
166 fault_if_from_uspace(istate
, "Unhandled exception %u.", n
);
167 panic_badtrap(istate
, n
, "Unhandled exception %u.", n
);
170 static _NO_TRACE
void
171 fault_from_uspace_core(istate_t
*istate
, const char *fmt
, va_list args
)
173 printf("Task %s (%" PRIu64
") killed due to an exception at "
174 "program counter %p.\n", TASK
->name
, TASK
->taskid
,
175 (void *) istate_get_pc(istate
));
177 istate_decode(istate
);
178 stack_trace_istate(istate
);
180 printf("Kill message: ");
184 task_kill_self(true);
187 /** Terminate thread and task after the exception came from userspace.
190 _NO_TRACE
void fault_from_uspace(istate_t
*istate
, const char *fmt
, ...)
195 fault_from_uspace_core(istate
, fmt
, args
);
199 /** Terminate thread and task if exception came from userspace.
202 _NO_TRACE
void fault_if_from_uspace(istate_t
*istate
, const char *fmt
, ...)
204 if (!istate_from_uspace(istate
))
209 fault_from_uspace_core(istate
, fmt
, args
);
213 /** Get istate structure of a thread.
215 * Get pointer to the istate structure at the bottom of the kernel stack.
217 * This function can be called in interrupt or user context. In interrupt
218 * context the istate structure is created by the low-level exception
219 * handler. In user context the istate structure is created by the
220 * low-level syscall handler.
222 istate_t
*istate_get(thread_t
*thread
)
225 * The istate structure should be right at the bottom of the kernel
228 return (istate_t
*) &thread
->kstack
[MEM_STACK_SIZE
- sizeof(istate_t
)];
231 #ifdef CONFIG_KCONSOLE
233 static char flag_buf
[MAX_CMDLINE
+ 1];
235 /** Print all exceptions
238 _NO_TRACE
static int cmd_exc_print(cmd_arg_t
*argv
)
242 if (str_cmp(flag_buf
, "-a") == 0)
244 else if (str_cmp(flag_buf
, "") == 0)
247 printf("Unknown argument \"%s\".\n", flag_buf
);
255 irq_spinlock_lock(&exctbl_lock
, true);
258 printf("[exc ] [description ] [count ] [cycles ]"
259 " [handler ] [symbol\n");
264 printf("[exc ] [description ] [count ] [cycles ]"
266 printf(" [symbol\n");
270 for (i
= 0; i
< IVT_ITEMS
; i
++) {
271 if ((!excs_all
) && (!exc_table
[i
].hot
))
277 order_suffix(exc_table
[i
].count
, &count
, &count_suffix
);
282 order_suffix(exc_table
[i
].cycles
, &cycles
, &cycles_suffix
);
285 symtab_fmt_name_lookup((sysarg_t
) exc_table
[i
].handler
);
288 printf("%-8u %-20s %9" PRIu64
"%c %9" PRIu64
"%c %10p %s\n",
289 i
+ IVT_FIRST
, exc_table
[i
].name
, count
, count_suffix
,
290 cycles
, cycles_suffix
, exc_table
[i
].handler
, symbol
);
292 PAGING(rows
, 1, irq_spinlock_unlock(&exctbl_lock
, true),
293 irq_spinlock_lock(&exctbl_lock
, true));
297 printf("%-8u %-20s %9" PRIu64
"%c %9" PRIu64
"%c %18p\n",
298 i
+ IVT_FIRST
, exc_table
[i
].name
, count
, count_suffix
,
299 cycles
, cycles_suffix
, exc_table
[i
].handler
);
300 printf(" %s\n", symbol
);
302 PAGING(rows
, 2, irq_spinlock_unlock(&exctbl_lock
, true),
303 irq_spinlock_lock(&exctbl_lock
, true));
307 irq_spinlock_unlock(&exctbl_lock
, true);
308 #else /* (IVT_ITEMS > 0) */
310 printf("No exception table%s.\n", excs_all
? " (showing all exceptions)" : "");
312 #endif /* (IVT_ITEMS > 0) */
317 static cmd_arg_t exc_argv
= {
318 .type
= ARG_TYPE_STRING_OPTIONAL
,
320 .len
= sizeof(flag_buf
)
323 static cmd_info_t exc_info
= {
325 .description
= "Print exception table (use -a for all exceptions).",
326 .func
= cmd_exc_print
,
332 #endif /* CONFIG_KCONSOLE */
334 /** Initialize generic exception handling support
344 for (i
= 0; i
< IVT_ITEMS
; i
++)
345 exc_register(i
, "undef", false, (iroutine_t
) exc_undef
);
348 #ifdef CONFIG_KCONSOLE
349 cmd_initialize(&exc_info
);
350 if (!cmd_register(&exc_info
))
351 printf("Cannot register command %s\n", exc_info
.name
);