Annotation of prex-old/sys/kern/exception.c, Revision 1.1.1.1
1.1 nbrk 1: /*-
2: * Copyright (c) 2005-2007, Kohsuke Ohtani
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: * 1. Redistributions of source code must retain the above copyright
9: * notice, this list of conditions and the following disclaimer.
10: * 2. Redistributions in binary form must reproduce the above copyright
11: * notice, this list of conditions and the following disclaimer in the
12: * documentation and/or other materials provided with the distribution.
13: * 3. Neither the name of the author nor the names of any co-contributors
14: * may be used to endorse or promote products derived from this software
15: * without specific prior written permission.
16: *
17: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27: * SUCH DAMAGE.
28: */
29:
30: /*
31: * exception.c - exception handling routines
32: */
33:
34: /**
35: * An user mode task can specify its own exception handler with
36: * exception_setup() system call.
37: *
38: * There are two different types of exceptions in a system - H/W and
39: * S/W exception. The kernel determines to which thread it delivers
40: * depending on the exception type.
41: *
42: * - H/W exception
43: *
44: * This type of exception is caused by H/W trap & fault. The
45: * exception will be sent to the thread which caused the trap.
46: * If no handler is specified by the task, it will be terminated
47: * by the kernel immediately.
48: *
49: * - S/W exception
50: *
51: * The user mode task can send S/W exception to another task by
52: * exception_raise() system call.
53: * The exception will be sent to the thread that is sleeping with
54: * exception_wait() call. If no thread is waiting for the exception,
55: * the exception is sent to the first thread in the target task.
56: *
57: * Kernel supports 32 types of exceptions. The following pre-defined
58: * exceptions are raised by kernel itself.
59: *
60: * Exception Type Reason
61: * --------- ---- -----------------------
62: * SIGILL h/w illegal instruction
63: * SIGTRAP h/w break point
64: * SIGFPE h/w math error
65: * SIGSEGV h/w invalid memory access
66: * SIGALRM s/w alarm event
67: *
68: * The POSIX emulation library will setup own exception handler to
69: * convert the Prex exceptions into UNIX signals. It will maintain its
70: * own signal mask, and transfer control to the POSIX signal handler.
71: */
72:
73: #include <kernel.h>
74: #include <event.h>
75: #include <task.h>
76: #include <thread.h>
77: #include <sched.h>
78: #include <task.h>
79: #include <irq.h>
80: #include <exception.h>
81:
82: static struct event exception_event;
83:
84: /*
85: * Install an exception handler for the current task.
86: * NULL can be specified as handler to remove current handler.
87: * If handler is removed, all pending exceptions are discarded
88: * immediately. In this case, all threads blocked in exception_wait()
89: * are unblocked.
90: *
91: * Only one exception handler can be set per task. If the previous
92: * handler exists in task, exception_setup() just override that
93: * handler.
94: */
95: int
96: exception_setup(void (*handler)(int, u_long))
97: {
98: task_t self;
99: list_t head, n;
100: thread_t th;
101:
102: if (handler != NULL && !user_area(handler))
103: return EFAULT;
104:
105: sched_lock();
106: self = cur_task();
107: if (self->exc_handler && handler == NULL) {
108: /*
109: * Remove existing exception handler. Do clean up
110: * job for all threads in the target task.
111: */
112: head = &self->threads;
113: for (n = list_first(head); n != head; n = list_next(n)) {
114: /*
115: * Clear pending exceptions.
116: */
117: th = list_entry(n, struct thread, task_link);
118: irq_lock();
119: th->exc_bitmap = 0;
120: irq_unlock();
121: /*
122: * If the thread is waiting for an exception,
123: * cancel it.
124: */
125: if (th->sleep_event == &exception_event)
126: sched_unsleep(th, SLP_BREAK);
127: }
128: }
129: self->exc_handler = handler;
130: sched_unlock();
131: return 0;
132: }
133:
134: /*
135: * exception_raise - raise an exception for specified task.
136: * @task: task id
137: * @exc: exception code
138: *
139: * The exception pending flag is marked here, and it is processed
140: * by exception_deliver() later. If the task want to raise an
141: * exception to another task, the caller task must have CAP_KILL
142: * capability. If the exception is sent to the kernel task, this
143: * routine just returns error.
144: */
145: int
146: exception_raise(task_t task, int exc)
147: {
148: int err;
149:
150: sched_lock();
151:
152: if (!task_valid(task)) {
153: err = ESRCH;
154: } else if (task != cur_task() && !task_capable(CAP_KILL)) {
155: err = EPERM;
156: } else if (task == &kern_task || task->exc_handler == NULL ||
157: list_empty(&task->threads)) {
158: err = EPERM;
159: } else {
160: err = exception_post(task, exc);
161: }
162: sched_unlock();
163: return err;
164: }
165:
166: /*
167: * Post an exception to the specified task.
168: */
169: int
170: exception_post(task_t task, int exc)
171: {
172: list_t head, n;
173: thread_t th;
174:
175: if (exc < 0 || exc >= NR_EXCS)
176: return EINVAL;
177:
178: /*
179: * Determine which thread should we send an exception.
180: * First, search the thread that is waiting an exception by
181: * calling exception_wait(). Then, if no thread is waiting
182: * exceptions, it is sent to the master thread in task.
183: */
184: head = &task->threads;
185: for (n = list_first(head); n != head; n = list_next(n)) {
186: th = list_entry(n, struct thread, task_link);
187: if (th->sleep_event == &exception_event)
188: break;
189: }
190: if (n == head) {
191: n = list_first(head);
192: th = list_entry(n, struct thread, task_link);
193: }
194: /*
195: * Mark pending bit for this exception.
196: */
197: irq_lock();
198: th->exc_bitmap |= (1 << exc);
199: irq_unlock();
200:
201: /*
202: * Wakeup the target thread regardless of its waiting
203: * event.
204: */
205: sched_unsleep(th, SLP_INTR);
206:
207: return 0;
208: }
209:
210: /*
211: * exception_wait - block a current thread until some exceptions are
212: * raised to the current thread.
213: * @exc: exception code returned.
214: *
215: * The routine returns EINTR on success.
216: */
217: int
218: exception_wait(int *exc)
219: {
220: int i, rc;
221:
222: if (cur_task()->exc_handler == NULL)
223: return EINVAL;
224: if (!user_area(exc))
225: return EFAULT;
226:
227: sched_lock();
228:
229: /*
230: * Sleep until some exceptions occur.
231: */
232: rc = sched_sleep(&exception_event);
233: if (rc == SLP_BREAK) {
234: sched_unlock();
235: return EINVAL;
236: }
237: irq_lock();
238: for (i = 0; i < NR_EXCS; i++) {
239: if (cur_thread->exc_bitmap & (1 << i))
240: break;
241: }
242: irq_unlock();
243: ASSERT(i != NR_EXCS);
244: sched_unlock();
245:
246: if (umem_copyout(&i, exc, sizeof(int)))
247: return EFAULT;
248: return EINTR;
249: }
250:
251: /*
252: * Mark an exception flag for the current thread.
253: *
254: * This is called from architecture dependent code when H/W trap is
255: * occurred. If current task does not have exception handler, then
256: * current task will be terminated.
257: * This routine may be called at interrupt level.
258: */
259: void
260: exception_mark(int exc)
261: {
262: ASSERT(exc > 0 && exc < NR_EXCS);
263:
264: /* Mark pending bit */
265: irq_lock();
266: cur_thread->exc_bitmap |= (1 << exc);
267: irq_unlock();
268: }
269:
270: /*
271: * Check if pending exception exists for current task, and deliver
272: * it to the exception handler if needed.
273: * All exception is delivered at the time when the control goes back
274: * to the user mode.
275: * This routine is called from architecture dependent code.
276: * Some application may use longjmp() during its signal handler.
277: * So, current context must be saved to user mode stack.
278: */
279: void
280: exception_deliver(void)
281: {
282: thread_t th = cur_thread;
283: task_t self = cur_task();
284: void (*handler)(int, u_long);
285: uint32_t bitmap;
286: int exc;
287:
288: sched_lock();
289: irq_lock();
290: bitmap = th->exc_bitmap;
291: irq_unlock();
292:
293: if (bitmap != 0) {
294: /*
295: * Find a pending exception.
296: */
297: for (exc = 0; exc < NR_EXCS; exc++) {
298: if (bitmap & (1 << exc))
299: break;
300: }
301: handler = self->exc_handler;
302: if (handler == NULL) {
303: printk("Exception #%d is not handled by task.\n", exc);
304: printk("Terminate task:%s (id:%x)\n",
305: self->name ? self->name : "no name", self);
306: task_terminate(self);
307: goto out;
308: }
309: /*
310: * Transfer control to an exception handler.
311: */
312: context_save(&th->context, exc);
313: context_set(&th->context, CTX_UENTRY, (u_long)handler);
314:
315: irq_lock();
316: th->exc_bitmap &= ~(1 << exc);
317: irq_unlock();
318: }
319: out:
320: sched_unlock();
321: }
322:
323: /*
324: * exception_return() is called from exception handler to restore
325: * the original context.
326: * @regs: context pointer which is passed to exception handler.
327: *
328: * TODO: should validate passed data area.
329: */
330: int
331: exception_return(void *regs)
332: {
333:
334: if ((regs == NULL) || !user_area(regs))
335: return EFAULT;
336:
337: context_restore(&cur_thread->context, regs);
338: return 0;
339: }
340:
341: void
342: exception_init(void)
343: {
344:
345: event_init(&exception_event, "exception");
346: }
CVSweb