1 | /* PowerPC exception handling middleware; consult README for more |
---|
2 | * information. |
---|
3 | * |
---|
4 | * Author: Till Straumann <strauman@slac.stanford.edu>, 2007 |
---|
5 | * |
---|
6 | * The license and distribution terms for this file may be |
---|
7 | * found in found in the file LICENSE in this distribution or at |
---|
8 | * http://www.rtems.com/license/LICENSE. |
---|
9 | * |
---|
10 | * $Id$ |
---|
11 | */ |
---|
12 | |
---|
13 | #include <stdint.h> |
---|
14 | #include <string.h> |
---|
15 | |
---|
16 | #include <rtems.h> |
---|
17 | #include <rtems/score/cpu.h> |
---|
18 | #include <libcpu/raw_exception.h> |
---|
19 | #include <libcpu/spr.h> |
---|
20 | #include <rtems/score/apiext.h> |
---|
21 | |
---|
22 | #include "vectors.h" |
---|
23 | #include "ppc_exc_bspsupp.h" |
---|
24 | |
---|
25 | /* offset into min-prolog where vector # is hardcoded */ |
---|
26 | #define PPC_EXC_PROLOG_VEC_OFFSET 2 |
---|
27 | |
---|
28 | /* Provide temp. storage space for a few registers. |
---|
29 | * This is used by the assembly code prior to setting up |
---|
30 | * the stack. |
---|
31 | * One set is needed for each exception type with its |
---|
32 | * own SRR0/SRR1 pair since such exceptions may nest. |
---|
33 | * |
---|
34 | * NOTE: The assembly code needs these variables to |
---|
35 | * be in the .sdata section and accesses them |
---|
36 | * via R13. |
---|
37 | */ |
---|
38 | uint32_t ppc_exc_lock_std = 0; |
---|
39 | uint32_t ppc_exc_lock_crit = 0; |
---|
40 | uint32_t ppc_exc_lock_mchk = 0; |
---|
41 | |
---|
42 | uint32_t ppc_exc_vector_register_std = 0; |
---|
43 | uint32_t ppc_exc_vector_register_crit = 0; |
---|
44 | uint32_t ppc_exc_vector_register_mchk = 0; |
---|
45 | |
---|
46 | /* MSR bits to enable once critical status info is saved and the stack |
---|
47 | * is switched; must be set depending on CPU type |
---|
48 | * |
---|
49 | * Default is set here for classic PPC CPUs with a MMU |
---|
50 | * but is overridden from vectors_init.c |
---|
51 | */ |
---|
52 | uint32_t ppc_exc_msr_bits = MSR_IR | MSR_DR | MSR_RI; |
---|
53 | |
---|
54 | int ppc_exc_handler_default( BSP_Exception_frame *f, unsigned int vector) |
---|
55 | { |
---|
56 | return 1; |
---|
57 | } |
---|
58 | |
---|
59 | /* Table of C-handlers */ |
---|
60 | ppc_exc_handler_t ppc_exc_handler_table [LAST_VALID_EXC + 1] = { |
---|
61 | [0 ... LAST_VALID_EXC] = ppc_exc_handler_default |
---|
62 | }; |
---|
63 | |
---|
64 | ppc_exc_handler_t ppc_exc_get_handler( unsigned vector) |
---|
65 | { |
---|
66 | ppc_exc_handler_t handler = NULL; |
---|
67 | if (vector > LAST_VALID_EXC) { |
---|
68 | return 0; |
---|
69 | } |
---|
70 | if (ppc_exc_handler_table [vector] != ppc_exc_handler_default) { |
---|
71 | handler = ppc_exc_handler_table [vector]; |
---|
72 | } |
---|
73 | return handler; |
---|
74 | } |
---|
75 | |
---|
76 | int ppc_exc_set_handler( unsigned vector, ppc_exc_handler_t handler) |
---|
77 | { |
---|
78 | if (vector > LAST_VALID_EXC) { |
---|
79 | return -1; |
---|
80 | } |
---|
81 | if (handler == NULL) { |
---|
82 | ppc_exc_handler_table [vector] = ppc_exc_handler_default; |
---|
83 | } else { |
---|
84 | ppc_exc_handler_table [vector] = handler; |
---|
85 | } |
---|
86 | return 0; |
---|
87 | } |
---|
88 | |
---|
89 | void |
---|
90 | ppc_exc_wrapup( BSP_Exception_frame *f) |
---|
91 | { |
---|
92 | /* dispatch_disable level is decremented from assembly code. */ |
---|
93 | if ( _Context_Switch_necessary ) { |
---|
94 | /* FIXME: I believe it should be OK to re-enable |
---|
95 | * interrupts around the execution of _Thread_Dispatch(); |
---|
96 | */ |
---|
97 | _Thread_Dispatch(); |
---|
98 | } else if ( _ISR_Signals_to_thread_executing ) { |
---|
99 | _ISR_Signals_to_thread_executing = 0; |
---|
100 | /* |
---|
101 | * Process pending signals that have not already been |
---|
102 | * processed by _Thread_Dispatch. This happens quite |
---|
103 | * unfrequently : the ISR must have posted an action |
---|
104 | * to the current running thread. |
---|
105 | */ |
---|
106 | if ( _Thread_Do_post_task_switch_extension || |
---|
107 | _Thread_Executing->do_post_task_switch_extension ) { |
---|
108 | _Thread_Executing->do_post_task_switch_extension = false; |
---|
109 | _API_extensions_Run_postswitch(); |
---|
110 | } |
---|
111 | } |
---|
112 | } |
---|
113 | |
---|
114 | void |
---|
115 | ppc_exc_min_prolog_expand(ppc_exc_min_prolog_t buf, ppc_exc_min_prolog_template_t templ, uint16_t vec) |
---|
116 | { |
---|
117 | memcpy(&buf[0], templ, sizeof(ppc_exc_min_prolog_t)); |
---|
118 | /* fixup the vector */ |
---|
119 | buf[PPC_EXC_PROLOG_VEC_OFFSET] = (buf[PPC_EXC_PROLOG_VEC_OFFSET] & 0xffff8000) | (vec & 0x7fff); |
---|
120 | } |
---|
121 | |
---|
122 | #undef TESTING |
---|
123 | #ifdef TESTING |
---|
124 | |
---|
125 | static void noop(const struct __rtems_raw_except_connect_data__*x) {} |
---|
126 | |
---|
127 | rtems_raw_except_connect_data exc_conn = { |
---|
128 | exceptIndex: ASM_SYS_VECTOR, |
---|
129 | hdl : { |
---|
130 | vector: ASM_SYS_VECTOR, |
---|
131 | raw_hdl: 0, |
---|
132 | raw_hdl_size: 0 |
---|
133 | }, |
---|
134 | on : noop, |
---|
135 | off : noop, |
---|
136 | isOn : 0 /* never used AFAIK */ |
---|
137 | }; |
---|
138 | |
---|
139 | void |
---|
140 | ppc_exc_raise() |
---|
141 | { |
---|
142 | asm volatile("li 3, 0xffffdead; sc"); |
---|
143 | } |
---|
144 | |
---|
145 | |
---|
146 | int |
---|
147 | exc_conn_do() |
---|
148 | { |
---|
149 | exc_conn.hdl.raw_hdl = ppc_exc_min_prolog_auto; |
---|
150 | exc_conn.hdl.raw_hdl_size = 16; |
---|
151 | return ppc_set_exception(&exc_conn); |
---|
152 | } |
---|
153 | #endif |
---|