source: mainline/kernel/generic/src/interrupt/interrupt.c@ 314f4b59

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 314f4b59 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
RevLine 
[a7fdfe1]1/*
[df4ed85]2 * Copyright (c) 2005 Ondrej Palkovsky
[a7fdfe1]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 */
[b45c443]28
[cc73a8a1]29/** @addtogroup genericinterrupt
[b45c443]30 * @{
31 */
[cf26ba9]32/**
[b45c443]33 * @file
[da1bafb]34 * @brief Interrupt redirector.
[cf26ba9]35 *
36 * This file provides means of registering interrupt handlers
37 * by kernel functions and calling the handlers when interrupts
38 * occur.
[da1bafb]39 *
[cf26ba9]40 */
41
[63e27ef]42#include <assert.h>
[973be64e]43#include <interrupt.h>
[aace6624]44#include <console/kconsole.h>
45#include <console/console.h>
[0132630]46#include <console/cmd.h>
[a074b4f]47#include <synch/mutex.h>
48#include <time/delay.h>
49#include <macros.h>
[aace6624]50#include <panic.h>
51#include <print.h>
[8f4f444]52#include <stdarg.h>
[aace6624]53#include <symtab.h>
[a2a00e8]54#include <proc/thread.h>
[8eec3c8]55#include <arch/cycle.h>
[e4d96e9]56#include <arch/stack.h>
[8eec3c8]57#include <str.h>
[7a0359b]58#include <trace.h>
[a7fdfe1]59
[8eec3c8]60exc_table_t exc_table[IVT_ITEMS];
61IRQ_SPINLOCK_INITIALIZE(exctbl_lock);
[aace6624]62
63/** Register exception handler
[da1bafb]64 *
[b3b7e14a]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.
[da1bafb]72 *
[aace6624]73 */
[b3b7e14a]74iroutine_t exc_register(unsigned int n, const char *name, bool hot,
75 iroutine_t handler)
[973be64e]76{
[b3b7e14a]77#if (IVT_ITEMS > 0)
[63e27ef]78 assert(n < IVT_ITEMS);
[b3b7e14a]79#endif
[a35b458]80
[8eec3c8]81 irq_spinlock_lock(&exctbl_lock, true);
[a35b458]82
[b3b7e14a]83 iroutine_t old = exc_table[n].handler;
84 exc_table[n].handler = handler;
[aace6624]85 exc_table[n].name = name;
[b3b7e14a]86 exc_table[n].hot = hot;
[8eec3c8]87 exc_table[n].cycles = 0;
88 exc_table[n].count = 0;
[a35b458]89
[8eec3c8]90 irq_spinlock_unlock(&exctbl_lock, true);
[a35b458]91
[973be64e]92 return old;
93}
[a7fdfe1]94
[aace6624]95/** Dispatch exception according to exception table
96 *
[973be64e]97 * Called directly from the assembler code.
98 * CPU is interrupts_disable()'d.
[da1bafb]99 *
[973be64e]100 */
[7a0359b]101NO_TRACE void exc_dispatch(unsigned int n, istate_t *istate)
[973be64e]102{
[b3b7e14a]103#if (IVT_ITEMS > 0)
[63e27ef]104 assert(n < IVT_ITEMS);
[b3b7e14a]105#endif
[a35b458]106
[a2a00e8]107 /* Account user cycles */
[cd98e594]108 if (THREAD) {
[da1bafb]109 irq_spinlock_lock(&THREAD->lock, false);
[b584cd4]110 thread_update_accounting(true);
[da1bafb]111 irq_spinlock_unlock(&THREAD->lock, false);
[cd98e594]112 }
[a35b458]113
[181a746]114 /* Account CPU usage if it woke up from sleep */
115 if (CPU && CPU->idle) {
[04e3d9f]116 irq_spinlock_lock(&CPU->lock, false);
[181a746]117 uint64_t now = get_cycle();
118 CPU->idle_cycles += now - CPU->last_cycle;
119 CPU->last_cycle = now;
120 CPU->idle = false;
[04e3d9f]121 irq_spinlock_unlock(&CPU->lock, false);
[d0c82c5]122 }
[a35b458]123
[b584cd4]124 uint64_t begin_cycle = get_cycle();
[a35b458]125
[3ff2b54]126#ifdef CONFIG_UDEBUG
[da1bafb]127 if (THREAD)
128 THREAD->udebug.uspace_state = istate;
[3ff2b54]129#endif
[a35b458]130
[b3b7e14a]131 exc_table[n].handler(n + IVT_FIRST, istate);
[a35b458]132
[3ff2b54]133#ifdef CONFIG_UDEBUG
[da1bafb]134 if (THREAD)
135 THREAD->udebug.uspace_state = NULL;
[3ff2b54]136#endif
[a35b458]137
[0dbc4e7]138 /* This is a safe place to exit exiting thread */
[da1bafb]139 if ((THREAD) && (THREAD->interrupted) && (istate_from_uspace(istate)))
[0dbc4e7]140 thread_exit();
[a35b458]141
[8eec3c8]142 /* Account exception handling */
143 uint64_t end_cycle = get_cycle();
[a35b458]144
[decfbe56]145 irq_spinlock_lock(&exctbl_lock, false);
[8eec3c8]146 exc_table[n].cycles += end_cycle - begin_cycle;
147 exc_table[n].count++;
[decfbe56]148 irq_spinlock_unlock(&exctbl_lock, false);
[a35b458]149
[8eec3c8]150 /* Do not charge THREAD for exception cycles */
[cd98e594]151 if (THREAD) {
[da1bafb]152 irq_spinlock_lock(&THREAD->lock, false);
[8eec3c8]153 THREAD->last_cycle = end_cycle;
[da1bafb]154 irq_spinlock_unlock(&THREAD->lock, false);
[cd98e594]155 }
[aace6624]156}
157
[da1bafb]158/** Default 'null' exception handler
159 *
160 */
[7a0359b]161NO_TRACE static void exc_undef(unsigned int n, istate_t *istate)
[aace6624]162{
[214ec25c]163 fault_if_from_uspace(istate, "Unhandled exception %u.", n);
[4d1be48]164 panic_badtrap(istate, n, "Unhandled exception %u.", n);
[aace6624]165}
166
[908bb96]167static NO_TRACE
168void fault_from_uspace_core(istate_t *istate, const char *fmt, va_list args)
[a074b4f]169{
[908bb96]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));
[a35b458]173
[908bb96]174 istate_decode(istate);
175 stack_trace_istate(istate);
[a35b458]176
[908bb96]177 printf("Kill message: ");
178 vprintf(fmt, args);
179 printf("\n");
[a35b458]180
[8f4f444]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{
[da1bafb]189 va_list args;
[8f4f444]190
[a074b4f]191 va_start(args, fmt);
[8f4f444]192 fault_from_uspace_core(istate, fmt, args);
[a074b4f]193 va_end(args);
[8f4f444]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;
[a35b458]203
[8f4f444]204 va_list args;
205 va_start(args, fmt);
206 fault_from_uspace_core(istate, fmt, args);
207 va_end(args);
[a074b4f]208}
209
[1ad52de]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 */
[63594c0]219istate_t *istate_get(thread_t *thread)
220{
[1ad52de]221 /*
222 * The istate structure should be right at the bottom of the kernel
[e4d96e9]223 * memory stack.
[1ad52de]224 */
[e4d96e9]225 return (istate_t *) &thread->kstack[MEM_STACK_SIZE - sizeof(istate_t)];
[63594c0]226}
227
[76fca31]228#ifdef CONFIG_KCONSOLE
229
[b3b7e14a]230static char flag_buf[MAX_CMDLINE + 1];
231
[da1bafb]232/** Print all exceptions
233 *
234 */
[7a0359b]235NO_TRACE static int cmd_exc_print(cmd_arg_t *argv)
[aace6624]236{
[b3b7e14a]237 bool excs_all;
[a35b458]238
[b3b7e14a]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 }
[a35b458]247
[6c441cf8]248#if (IVT_ITEMS > 0)
[43b1e86]249 unsigned int i;
[b3b7e14a]250 unsigned int rows;
[a35b458]251
[8eec3c8]252 irq_spinlock_lock(&exctbl_lock, true);
[a35b458]253
[c70d693]254#ifdef __32_BITS__
[b3b7e14a]255 printf("[exc ] [description ] [count ] [cycles ]"
256 " [handler ] [symbol\n");
257 rows = 1;
[c70d693]258#endif
[a35b458]259
[c70d693]260#ifdef __64_BITS__
[b3b7e14a]261 printf("[exc ] [description ] [count ] [cycles ]"
262 " [handler ]\n");
263 printf(" [symbol\n");
264 rows = 2;
[c70d693]265#endif
[a35b458]266
[43b1e86]267 for (i = 0; i < IVT_ITEMS; i++) {
[b3b7e14a]268 if ((!excs_all) && (!exc_table[i].hot))
269 continue;
[a35b458]270
[8eec3c8]271 uint64_t count;
272 char count_suffix;
[a35b458]273
[8eec3c8]274 order_suffix(exc_table[i].count, &count, &count_suffix);
[a35b458]275
[8eec3c8]276 uint64_t cycles;
277 char cycles_suffix;
[a35b458]278
[8eec3c8]279 order_suffix(exc_table[i].cycles, &cycles, &cycles_suffix);
[a35b458]280
[8eec3c8]281 const char *symbol =
[96b02eb9]282 symtab_fmt_name_lookup((sysarg_t) exc_table[i].handler);
[a35b458]283
[c70d693]284#ifdef __32_BITS__
[b3b7e14a]285 printf("%-8u %-20s %9" PRIu64 "%c %9" PRIu64 "%c %10p %s\n",
[8eec3c8]286 i + IVT_FIRST, exc_table[i].name, count, count_suffix,
[b3b7e14a]287 cycles, cycles_suffix, exc_table[i].handler, symbol);
[a35b458]288
[b3b7e14a]289 PAGING(rows, 1, irq_spinlock_unlock(&exctbl_lock, true),
290 irq_spinlock_lock(&exctbl_lock, true));
[c70d693]291#endif
[a35b458]292
[c70d693]293#ifdef __64_BITS__
[b3b7e14a]294 printf("%-8u %-20s %9" PRIu64 "%c %9" PRIu64 "%c %18p\n",
[8eec3c8]295 i + IVT_FIRST, exc_table[i].name, count, count_suffix,
[b3b7e14a]296 cycles, cycles_suffix, exc_table[i].handler);
297 printf(" %s\n", symbol);
[a35b458]298
[b3b7e14a]299 PAGING(rows, 2, irq_spinlock_unlock(&exctbl_lock, true),
300 irq_spinlock_lock(&exctbl_lock, true));
301#endif
[aace6624]302 }
[a35b458]303
[8eec3c8]304 irq_spinlock_unlock(&exctbl_lock, true);
[b3b7e14a]305#else /* (IVT_ITEMS > 0) */
[a35b458]306
[b3b7e14a]307 printf("No exception table%s.\n", excs_all ? " (showing all exceptions)" : "");
[a35b458]308
[b3b7e14a]309#endif /* (IVT_ITEMS > 0) */
[a35b458]310
[aace6624]311 return 1;
312}
313
[b3b7e14a]314static cmd_arg_t exc_argv = {
315 .type = ARG_TYPE_STRING_OPTIONAL,
316 .buffer = flag_buf,
317 .len = sizeof(flag_buf)
318};
319
[aace6624]320static cmd_info_t exc_info = {
[0132630]321 .name = "exc",
[b3b7e14a]322 .description = "Print exception table (use -a for all exceptions).",
[76fca31]323 .func = cmd_exc_print,
[aace6624]324 .help = NULL,
[b3b7e14a]325 .argc = 1,
326 .argv = &exc_argv
[aace6624]327};
328
[da1bafb]329#endif /* CONFIG_KCONSOLE */
[76fca31]330
[da1bafb]331/** Initialize generic exception handling support
332 *
333 */
[aace6624]334void exc_init(void)
335{
[da1bafb]336 (void) exc_undef;
[a35b458]337
[da1bafb]338#if (IVT_ITEMS > 0)
339 unsigned int i;
[a35b458]340
[c70d693]341 for (i = 0; i < IVT_ITEMS; i++)
[b3b7e14a]342 exc_register(i, "undef", false, (iroutine_t) exc_undef);
[da1bafb]343#endif
[a35b458]344
[76fca31]345#ifdef CONFIG_KCONSOLE
[0132630]346 cmd_initialize(&exc_info);
[aace6624]347 if (!cmd_register(&exc_info))
[76fca31]348 printf("Cannot register command %s\n", exc_info.name);
349#endif
[973be64e]350}
[aace6624]351
[cc73a8a1]352/** @}
[b45c443]353 */
Note: See TracBrowser for help on using the repository browser.