source: mainline/kernel/generic/src/interrupt/interrupt.c@ eed4139

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since eed4139 was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

  • Property mode set to 100644
File size: 8.7 KB
Line 
1/*
2 * Copyright (c) 2005 Ondrej Palkovsky
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
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.
16 *
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.
27 */
28
29/** @addtogroup genericinterrupt
30 * @{
31 */
32/**
33 * @file
34 * @brief Interrupt redirector.
35 *
36 * This file provides means of registering interrupt handlers
37 * by kernel functions and calling the handlers when interrupts
38 * occur.
39 *
40 */
41
42#include <assert.h>
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>
49#include <macros.h>
50#include <panic.h>
51#include <print.h>
52#include <stdarg.h>
53#include <symtab.h>
54#include <proc/thread.h>
55#include <arch/cycle.h>
56#include <arch/stack.h>
57#include <str.h>
58#include <trace.h>
59
60exc_table_t exc_table[IVT_ITEMS];
61IRQ_SPINLOCK_INITIALIZE(exctbl_lock);
62
63/** Register exception handler
64 *
65 * @param n Exception number.
66 * @param name Description.
67 * @param hot Whether the exception is actually handled
68 * in any meaningful way.
69 * @param handler New exception handler.
70 *
71 * @return Previously registered exception handler.
72 *
73 */
74iroutine_t exc_register(unsigned int n, const char *name, bool hot,
75 iroutine_t handler)
76{
77#if (IVT_ITEMS > 0)
78 assert(n < IVT_ITEMS);
79#endif
80
81 irq_spinlock_lock(&exctbl_lock, true);
82
83 iroutine_t old = exc_table[n].handler;
84 exc_table[n].handler = handler;
85 exc_table[n].name = name;
86 exc_table[n].hot = hot;
87 exc_table[n].cycles = 0;
88 exc_table[n].count = 0;
89
90 irq_spinlock_unlock(&exctbl_lock, true);
91
92 return old;
93}
94
95/** Dispatch exception according to exception table
96 *
97 * Called directly from the assembler code.
98 * CPU is interrupts_disable()'d.
99 *
100 */
101NO_TRACE void exc_dispatch(unsigned int n, istate_t *istate)
102{
103#if (IVT_ITEMS > 0)
104 assert(n < IVT_ITEMS);
105#endif
106
107 /* Account user cycles */
108 if (THREAD) {
109 irq_spinlock_lock(&THREAD->lock, false);
110 thread_update_accounting(true);
111 irq_spinlock_unlock(&THREAD->lock, false);
112 }
113
114 /* Account CPU usage if it woke up from sleep */
115 if (CPU && CPU->idle) {
116 irq_spinlock_lock(&CPU->lock, false);
117 uint64_t now = get_cycle();
118 CPU->idle_cycles += now - CPU->last_cycle;
119 CPU->last_cycle = now;
120 CPU->idle = false;
121 irq_spinlock_unlock(&CPU->lock, false);
122 }
123
124 uint64_t begin_cycle = get_cycle();
125
126#ifdef CONFIG_UDEBUG
127 if (THREAD)
128 THREAD->udebug.uspace_state = istate;
129#endif
130
131 exc_table[n].handler(n + IVT_FIRST, istate);
132
133#ifdef CONFIG_UDEBUG
134 if (THREAD)
135 THREAD->udebug.uspace_state = NULL;
136#endif
137
138 /* This is a safe place to exit exiting thread */
139 if ((THREAD) && (THREAD->interrupted) && (istate_from_uspace(istate)))
140 thread_exit();
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
167static NO_TRACE
168void fault_from_uspace_core(istate_t *istate, const char *fmt, va_list args)
169{
170 printf("Task %s (%" PRIu64 ") killed due to an exception at "
171 "program counter %p.\n", TASK->name, TASK->taskid,
172 (void *) istate_get_pc(istate));
173
174 istate_decode(istate);
175 stack_trace_istate(istate);
176
177 printf("Kill message: ");
178 vprintf(fmt, args);
179 printf("\n");
180
181 task_kill_self(true);
182}
183
184/** Terminate thread and task after the exception came from userspace.
185 *
186 */
187NO_TRACE void fault_from_uspace(istate_t *istate, const char *fmt, ...)
188{
189 va_list args;
190
191 va_start(args, fmt);
192 fault_from_uspace_core(istate, fmt, args);
193 va_end(args);
194}
195
196/** Terminate thread and task if exception came from userspace.
197 *
198 */
199NO_TRACE void fault_if_from_uspace(istate_t *istate, const char *fmt, ...)
200{
201 if (!istate_from_uspace(istate))
202 return;
203
204 va_list args;
205 va_start(args, fmt);
206 fault_from_uspace_core(istate, fmt, args);
207 va_end(args);
208}
209
210/** Get istate structure of a thread.
211 *
212 * Get pointer to the istate structure at the bottom of the kernel stack.
213 *
214 * This function can be called in interrupt or user context. In interrupt
215 * context the istate structure is created by the low-level exception
216 * handler. In user context the istate structure is created by the
217 * low-level syscall handler.
218 */
219istate_t *istate_get(thread_t *thread)
220{
221 /*
222 * The istate structure should be right at the bottom of the kernel
223 * memory stack.
224 */
225 return (istate_t *) &thread->kstack[MEM_STACK_SIZE - sizeof(istate_t)];
226}
227
228#ifdef CONFIG_KCONSOLE
229
230static char flag_buf[MAX_CMDLINE + 1];
231
232/** Print all exceptions
233 *
234 */
235NO_TRACE static int cmd_exc_print(cmd_arg_t *argv)
236{
237 bool excs_all;
238
239 if (str_cmp(flag_buf, "-a") == 0)
240 excs_all = true;
241 else if (str_cmp(flag_buf, "") == 0)
242 excs_all = false;
243 else {
244 printf("Unknown argument \"%s\".\n", flag_buf);
245 return 1;
246 }
247
248#if (IVT_ITEMS > 0)
249 unsigned int i;
250 unsigned int rows;
251
252 irq_spinlock_lock(&exctbl_lock, true);
253
254#ifdef __32_BITS__
255 printf("[exc ] [description ] [count ] [cycles ]"
256 " [handler ] [symbol\n");
257 rows = 1;
258#endif
259
260#ifdef __64_BITS__
261 printf("[exc ] [description ] [count ] [cycles ]"
262 " [handler ]\n");
263 printf(" [symbol\n");
264 rows = 2;
265#endif
266
267 for (i = 0; i < IVT_ITEMS; i++) {
268 if ((!excs_all) && (!exc_table[i].hot))
269 continue;
270
271 uint64_t count;
272 char count_suffix;
273
274 order_suffix(exc_table[i].count, &count, &count_suffix);
275
276 uint64_t cycles;
277 char cycles_suffix;
278
279 order_suffix(exc_table[i].cycles, &cycles, &cycles_suffix);
280
281 const char *symbol =
282 symtab_fmt_name_lookup((sysarg_t) exc_table[i].handler);
283
284#ifdef __32_BITS__
285 printf("%-8u %-20s %9" PRIu64 "%c %9" PRIu64 "%c %10p %s\n",
286 i + IVT_FIRST, exc_table[i].name, count, count_suffix,
287 cycles, cycles_suffix, exc_table[i].handler, symbol);
288
289 PAGING(rows, 1, irq_spinlock_unlock(&exctbl_lock, true),
290 irq_spinlock_lock(&exctbl_lock, true));
291#endif
292
293#ifdef __64_BITS__
294 printf("%-8u %-20s %9" PRIu64 "%c %9" PRIu64 "%c %18p\n",
295 i + IVT_FIRST, exc_table[i].name, count, count_suffix,
296 cycles, cycles_suffix, exc_table[i].handler);
297 printf(" %s\n", symbol);
298
299 PAGING(rows, 2, irq_spinlock_unlock(&exctbl_lock, true),
300 irq_spinlock_lock(&exctbl_lock, true));
301#endif
302 }
303
304 irq_spinlock_unlock(&exctbl_lock, true);
305#else /* (IVT_ITEMS > 0) */
306
307 printf("No exception table%s.\n", excs_all ? " (showing all exceptions)" : "");
308
309#endif /* (IVT_ITEMS > 0) */
310
311 return 1;
312}
313
314static cmd_arg_t exc_argv = {
315 .type = ARG_TYPE_STRING_OPTIONAL,
316 .buffer = flag_buf,
317 .len = sizeof(flag_buf)
318};
319
320static cmd_info_t exc_info = {
321 .name = "exc",
322 .description = "Print exception table (use -a for all exceptions).",
323 .func = cmd_exc_print,
324 .help = NULL,
325 .argc = 1,
326 .argv = &exc_argv
327};
328
329#endif /* CONFIG_KCONSOLE */
330
331/** Initialize generic exception handling support
332 *
333 */
334void exc_init(void)
335{
336 (void) exc_undef;
337
338#if (IVT_ITEMS > 0)
339 unsigned int i;
340
341 for (i = 0; i < IVT_ITEMS; i++)
342 exc_register(i, "undef", false, (iroutine_t) exc_undef);
343#endif
344
345#ifdef CONFIG_KCONSOLE
346 cmd_initialize(&exc_info);
347 if (!cmd_register(&exc_info))
348 printf("Cannot register command %s\n", exc_info.name);
349#endif
350}
351
352/** @}
353 */
Note: See TracBrowser for help on using the repository browser.