|
0
|
1 /* ppc_stub.c - helper functions for stub, generic to all PowerPC processors |
|
|
2 * |
|
2
|
3 * Copyright (c) 1998,1999 Cygnus Solutions |
|
0
|
4 * |
|
|
5 * The authors hereby grant permission to use, copy, modify, distribute, |
|
|
6 * and license this software and its documentation for any purpose, provided |
|
|
7 * that existing copyright notices are retained in all copies and that this |
|
|
8 * notice is included verbatim in any distributions. No written agreement, |
|
|
9 * license, or royalty fee is required for any of the authorized uses. |
|
|
10 * Modifications to this software may be copyrighted by their authors |
|
|
11 * and need not follow the licensing terms described here, provided that |
|
|
12 * the new terms are clearly indicated on the first page of each file where |
|
|
13 * they apply. |
|
|
14 */ |
|
|
15 |
|
|
16 #include <stddef.h> |
|
|
17 |
|
|
18 #include <pkgconf/hal.h> |
|
|
19 |
|
|
20 #ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS |
|
|
21 |
|
2
|
22 #define CYGARC_HAL_COMMON_EXPORT_CPU_MACROS |
|
|
23 #include <cyg/hal/ppc_regs.h> |
|
0
|
24 |
|
|
25 #include <cyg/hal/hal_stub.h> |
|
|
26 #include <cyg/hal/hal_arch.h> |
|
|
27 #include <cyg/hal/hal_intr.h> |
|
|
28 |
|
|
29 #ifdef CYGDBG_HAL_DEBUG_GDB_THREAD_SUPPORT |
|
|
30 #include <cyg/hal/dbg-threads-api.h> // dbg_currthread_id |
|
|
31 #endif |
|
|
32 |
|
|
33 /* Given a trap value TRAP, return the corresponding signal. */ |
|
|
34 |
|
|
35 int __computeSignal (unsigned int trap_number) |
|
|
36 { |
|
|
37 switch (trap_number) |
|
|
38 { |
|
2
|
39 case CYGNUM_HAL_VECTOR_MACHINE_CHECK: |
|
0
|
40 /* Machine check */ |
|
2
|
41 case CYGNUM_HAL_VECTOR_DSI: |
|
0
|
42 /* Data access */ |
|
|
43 return SIGSEGV; |
|
|
44 |
|
2
|
45 case CYGNUM_HAL_VECTOR_ISI: |
|
0
|
46 /* Instruction access (Ifetch) */ |
|
2
|
47 case CYGNUM_HAL_VECTOR_ALIGNMENT: |
|
0
|
48 /* Data access */ |
|
|
49 return SIGBUS; |
|
|
50 |
|
2
|
51 case CYGNUM_HAL_VECTOR_INTERRUPT: |
|
0
|
52 /* External interrupt */ |
|
|
53 return SIGINT; |
|
|
54 |
|
2
|
55 case CYGNUM_HAL_VECTOR_TRACE: |
|
0
|
56 /* Instruction trace */ |
|
|
57 return SIGTRAP; |
|
|
58 |
|
2
|
59 case CYGNUM_HAL_VECTOR_PROGRAM: |
|
|
60 // The register PS contains the value of SRR1 at the time of |
|
|
61 // exception entry. Bits 11-15 contain information about the |
|
|
62 // cause of the exception. Bits 16-31 the PS (MSR) state. |
|
0
|
63 switch ((get_register (PS) >> 17) & 0xf){ |
|
|
64 case 1: /* trap */ |
|
|
65 return SIGTRAP; |
|
|
66 case 2: /* privileged instruction */ |
|
|
67 case 4: /* illegal instruction */ |
|
|
68 return SIGILL; |
|
|
69 case 8: /* floating point */ |
|
|
70 return SIGFPE; |
|
|
71 default: /* should never happen! */ |
|
|
72 return SIGTERM; |
|
|
73 } |
|
|
74 |
|
2
|
75 case CYGNUM_HAL_VECTOR_RESERVED_A: |
|
|
76 case CYGNUM_HAL_VECTOR_RESERVED_B: |
|
0
|
77 return SIGILL; |
|
|
78 |
|
2
|
79 case CYGNUM_HAL_VECTOR_FP_UNAVAILABLE: |
|
0
|
80 /* FPU disabled */ |
|
2
|
81 case CYGNUM_HAL_VECTOR_FP_ASSIST: |
|
0
|
82 /* FPU assist */ |
|
|
83 return SIGFPE; |
|
|
84 |
|
2
|
85 case CYGNUM_HAL_VECTOR_DECREMENTER: |
|
0
|
86 /* Decrementer alarm */ |
|
|
87 return SIGALRM; |
|
|
88 |
|
2
|
89 case CYGNUM_HAL_VECTOR_SYSTEM_CALL: |
|
0
|
90 /* System call */ |
|
|
91 return SIGSYS; |
|
|
92 |
|
2
|
93 #if defined(CYG_HAL_POWERPC_MPC8xx) |
|
|
94 case CYGNUM_HAL_VECTOR_SW_EMUL: |
|
0
|
95 /* A SW_EMUL is generated instead of PROGRAM for illegal |
|
|
96 instructions. */ |
|
|
97 return SIGILL; |
|
|
98 |
|
2
|
99 case CYGNUM_HAL_VECTOR_DATA_BP: |
|
|
100 case CYGNUM_HAL_VECTOR_INSTRUCTION_BP: |
|
|
101 case CYGNUM_HAL_VECTOR_PERIPHERAL_BP: |
|
|
102 case CYGNUM_HAL_VECTOR_NMI: |
|
0
|
103 /* Developer port debugging exceptions. */ |
|
|
104 return SIGTRAP; |
|
|
105 |
|
2
|
106 case CYGNUM_HAL_VECTOR_ITLB_MISS: |
|
|
107 case CYGNUM_HAL_VECTOR_DTLB_MISS: |
|
0
|
108 /* Software reload of TLB required. */ |
|
|
109 return SIGTRAP; |
|
|
110 |
|
2
|
111 case CYGNUM_HAL_VECTOR_ITLB_ERROR: |
|
0
|
112 /* Invalid instruction access. */ |
|
|
113 return SIGBUS; |
|
|
114 |
|
2
|
115 case CYGNUM_HAL_VECTOR_DTLB_ERROR: |
|
0
|
116 /* Invalid data access. */ |
|
|
117 return SIGSEGV; |
|
2
|
118 #endif // defined(CYG_HAL_POWERPC_MPC8xx) |
|
0
|
119 |
|
|
120 default: |
|
|
121 return SIGTERM; |
|
|
122 } |
|
|
123 } |
|
|
124 |
|
|
125 |
|
|
126 /* Return the trap number corresponding to the last-taken trap. */ |
|
|
127 |
|
|
128 int __get_trap_number (void) |
|
|
129 { |
|
|
130 // The vector is not not part of the GDB register set so get it |
|
|
131 // directly from the save context. |
|
|
132 return _hal_registers->vector >> 8; |
|
|
133 } |
|
|
134 |
|
|
135 /* Set the currently-saved pc register value to PC. This also updates NPC |
|
|
136 as needed. */ |
|
|
137 |
|
|
138 void set_pc (target_register_t pc) |
|
|
139 { |
|
|
140 put_register (PC, pc); |
|
|
141 } |
|
|
142 |
|
|
143 |
|
|
144 /*---------------------------------------------------------------------- |
|
|
145 * Single-step support |
|
|
146 */ |
|
|
147 |
|
|
148 /* Set things up so that the next user resume will execute one instruction. |
|
|
149 This may be done by setting breakpoints or setting a single step flag |
|
|
150 in the saved user registers, for example. */ |
|
|
151 |
|
|
152 static target_register_t irq_state; |
|
|
153 |
|
2
|
154 void __single_step (void) |
|
0
|
155 { |
|
|
156 target_register_t msr = get_register (PS); |
|
|
157 |
|
|
158 // Set single-step flag in the exception context. |
|
|
159 msr |= (MSR_SE | MSR_BE); |
|
|
160 // Disable interrupts. |
|
|
161 irq_state = msr & MSR_EE; |
|
|
162 msr &= ~MSR_EE; |
|
|
163 |
|
|
164 put_register (PS, msr); |
|
|
165 } |
|
|
166 |
|
|
167 /* Clear the single-step state. */ |
|
|
168 |
|
2
|
169 void __clear_single_step (void) |
|
0
|
170 { |
|
|
171 target_register_t msr = get_register (PS); |
|
|
172 |
|
|
173 // Clear single-step flag in the exception context. |
|
|
174 msr &= ~(MSR_SE | MSR_BE); |
|
|
175 // Restore interrupt state. |
|
|
176 // FIXME: Should check whether the executed instruction changed the |
|
|
177 // interrupt state - or single-stepping a MSR changing instruction |
|
|
178 // may result in a wrong EE. Not a very likely scenario though. |
|
|
179 msr |= irq_state; |
|
|
180 |
|
|
181 put_register (PS, msr); |
|
|
182 } |
|
|
183 |
|
|
184 |
|
2
|
185 void __install_breakpoints (void) |
|
0
|
186 { |
|
|
187 /* NOP since single-step HW exceptions are used instead of |
|
|
188 breakpoints. */ |
|
|
189 } |
|
|
190 |
|
2
|
191 void __clear_breakpoints (void) |
|
|
192 { |
|
|
193 } |
|
|
194 |
|
0
|
195 |
|
|
196 /* If the breakpoint we hit is in the breakpoint() instruction, return a |
|
|
197 non-zero value. */ |
|
|
198 |
|
|
199 int |
|
|
200 __is_breakpoint_function () |
|
|
201 { |
|
2
|
202 return get_register (PC) == (target_register_t)&CYG_LABEL_NAME(breakinst); |
|
0
|
203 } |
|
|
204 |
|
|
205 |
|
|
206 /* Skip the current instruction. Since this is only called by the |
|
|
207 stub when the PC points to a breakpoint or trap instruction, |
|
|
208 we can safely just skip 4. */ |
|
|
209 |
|
|
210 void __skipinst (void) |
|
|
211 { |
|
|
212 put_register (PC, get_register (PC) + 4); |
|
|
213 } |
|
|
214 |
|
|
215 #endif // CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS |