db_interface.c revision 1.12.6.6 1 1.12.6.6 thorpej /* $NetBSD: db_interface.c,v 1.12.6.6 2002/12/11 06:11:44 thorpej Exp $ */
2 1.12.6.2 nathanw /* $OpenBSD: db_interface.c,v 1.2 1996/12/28 06:21:50 rahnds Exp $ */
3 1.12.6.2 nathanw
4 1.12.6.2 nathanw #define USERACC
5 1.12.6.2 nathanw
6 1.12.6.2 nathanw #include "opt_ddb.h"
7 1.12.6.3 nathanw #include "opt_kgdb.h"
8 1.12.6.2 nathanw #include "opt_ppcarch.h"
9 1.12.6.2 nathanw
10 1.12.6.2 nathanw #include <sys/param.h>
11 1.12.6.2 nathanw #include <sys/proc.h>
12 1.12.6.2 nathanw #include <sys/systm.h>
13 1.12.6.2 nathanw
14 1.12.6.2 nathanw #include <dev/cons.h>
15 1.12.6.2 nathanw
16 1.12.6.2 nathanw #include <machine/db_machdep.h>
17 1.12.6.2 nathanw #include <machine/frame.h>
18 1.12.6.2 nathanw #ifdef PPC_IBM4XX
19 1.12.6.2 nathanw #include <machine/tlb.h>
20 1.12.6.2 nathanw #include <powerpc/spr.h>
21 1.12.6.2 nathanw #include <uvm/uvm_extern.h>
22 1.12.6.2 nathanw #endif
23 1.12.6.2 nathanw
24 1.12.6.3 nathanw #ifdef DDB
25 1.12.6.2 nathanw #include <ddb/db_sym.h>
26 1.12.6.2 nathanw #include <ddb/db_command.h>
27 1.12.6.2 nathanw #include <ddb/db_extern.h>
28 1.12.6.2 nathanw #include <ddb/db_access.h>
29 1.12.6.2 nathanw #include <ddb/db_output.h>
30 1.12.6.2 nathanw #include <ddb/ddbvar.h>
31 1.12.6.3 nathanw #endif
32 1.12.6.3 nathanw
33 1.12.6.3 nathanw #ifdef KGDB
34 1.12.6.3 nathanw #include <sys/kgdb.h>
35 1.12.6.3 nathanw #endif
36 1.12.6.3 nathanw
37 1.12.6.3 nathanw #include <dev/ofw/openfirm.h>
38 1.12.6.2 nathanw
39 1.12.6.2 nathanw int db_active = 0;
40 1.12.6.2 nathanw
41 1.12.6.5 nathanw db_regs_t ddb_regs;
42 1.12.6.2 nathanw
43 1.12.6.2 nathanw void ddb_trap(void); /* Call into trap_subr.S */
44 1.12.6.2 nathanw int ddb_trap_glue(struct trapframe *); /* Called from trap_subr.S */
45 1.12.6.2 nathanw #ifdef PPC_IBM4XX
46 1.12.6.2 nathanw static void db_ppc4xx_ctx(db_expr_t, int, db_expr_t, char *);
47 1.12.6.2 nathanw static void db_ppc4xx_pv(db_expr_t, int, db_expr_t, char *);
48 1.12.6.2 nathanw static void db_ppc4xx_reset(db_expr_t, int, db_expr_t, char *);
49 1.12.6.2 nathanw static void db_ppc4xx_tf(db_expr_t, int, db_expr_t, char *);
50 1.12.6.2 nathanw static void db_ppc4xx_dumptlb(db_expr_t, int, db_expr_t, char *);
51 1.12.6.2 nathanw #ifdef USERACC
52 1.12.6.2 nathanw static void db_ppc4xx_useracc(db_expr_t, int, db_expr_t, char *);
53 1.12.6.2 nathanw #endif
54 1.12.6.2 nathanw #endif /* PPC_IBM4XX */
55 1.12.6.2 nathanw
56 1.12.6.3 nathanw #ifdef DDB
57 1.12.6.2 nathanw void
58 1.12.6.2 nathanw cpu_Debugger()
59 1.12.6.2 nathanw {
60 1.12.6.2 nathanw ddb_trap();
61 1.12.6.2 nathanw }
62 1.12.6.3 nathanw #endif
63 1.12.6.2 nathanw
64 1.12.6.2 nathanw int
65 1.12.6.2 nathanw ddb_trap_glue(frame)
66 1.12.6.2 nathanw struct trapframe *frame;
67 1.12.6.2 nathanw {
68 1.12.6.2 nathanw if (!(frame->srr1 & PSL_PR)
69 1.12.6.4 nathanw && (frame->exc == EXC_TRC || frame->exc == EXC_RUNMODETRC
70 1.12.6.2 nathanw || (frame->exc == EXC_PGM
71 1.12.6.2 nathanw && (frame->srr1 & 0x20000))
72 1.12.6.2 nathanw || frame->exc == EXC_BPT)) {
73 1.12.6.3 nathanw int type = frame->exc;
74 1.12.6.3 nathanw if (type == EXC_PGM && (frame->srr1 & 0x20000)) {
75 1.12.6.3 nathanw type = T_BREAKPOINT;
76 1.12.6.3 nathanw }
77 1.12.6.3 nathanw return kdb_trap(type, frame);
78 1.12.6.2 nathanw }
79 1.12.6.2 nathanw return 0;
80 1.12.6.2 nathanw }
81 1.12.6.2 nathanw
82 1.12.6.2 nathanw int
83 1.12.6.2 nathanw kdb_trap(type, v)
84 1.12.6.2 nathanw int type;
85 1.12.6.2 nathanw void *v;
86 1.12.6.2 nathanw {
87 1.12.6.2 nathanw struct trapframe *frame = v;
88 1.12.6.2 nathanw
89 1.12.6.3 nathanw #ifdef DDB
90 1.12.6.2 nathanw switch (type) {
91 1.12.6.2 nathanw case T_BREAKPOINT:
92 1.12.6.2 nathanw case -1:
93 1.12.6.2 nathanw break;
94 1.12.6.2 nathanw default:
95 1.12.6.2 nathanw if (!db_onpanic && db_recover == 0)
96 1.12.6.2 nathanw return 0;
97 1.12.6.2 nathanw if (db_recover != 0) {
98 1.12.6.2 nathanw db_error("Faulted in DDB; continuing...\n");
99 1.12.6.2 nathanw /*NOTREACHED*/
100 1.12.6.2 nathanw }
101 1.12.6.2 nathanw }
102 1.12.6.3 nathanw #endif
103 1.12.6.2 nathanw
104 1.12.6.2 nathanw /* XXX Should switch to kdb's own stack here. */
105 1.12.6.2 nathanw
106 1.12.6.2 nathanw memcpy(DDB_REGS->r, frame->fixreg, 32 * sizeof(u_int32_t));
107 1.12.6.2 nathanw DDB_REGS->iar = frame->srr0;
108 1.12.6.2 nathanw DDB_REGS->msr = frame->srr1;
109 1.12.6.2 nathanw DDB_REGS->lr = frame->lr;
110 1.12.6.2 nathanw DDB_REGS->ctr = frame->ctr;
111 1.12.6.2 nathanw DDB_REGS->cr = frame->cr;
112 1.12.6.2 nathanw DDB_REGS->xer = frame->xer;
113 1.12.6.2 nathanw #ifdef PPC_IBM4XX
114 1.12.6.2 nathanw DDB_REGS->dear = frame->dear;
115 1.12.6.2 nathanw DDB_REGS->esr = frame->esr;
116 1.12.6.2 nathanw DDB_REGS->pid = frame->pid;
117 1.12.6.2 nathanw #endif
118 1.12.6.2 nathanw
119 1.12.6.3 nathanw #ifdef DDB
120 1.12.6.2 nathanw db_active++;
121 1.12.6.2 nathanw cnpollc(1);
122 1.12.6.2 nathanw db_trap(type, 0);
123 1.12.6.2 nathanw cnpollc(0);
124 1.12.6.2 nathanw db_active--;
125 1.12.6.3 nathanw #elif defined(KGDB)
126 1.12.6.3 nathanw if (!kgdb_trap(type, DDB_REGS))
127 1.12.6.3 nathanw return 0;
128 1.12.6.3 nathanw #endif
129 1.12.6.3 nathanw
130 1.12.6.3 nathanw /* KGDB isn't smart about advancing PC if we
131 1.12.6.3 nathanw * take a breakpoint trap after kgdb_active is set.
132 1.12.6.3 nathanw * Therefore, we help out here.
133 1.12.6.3 nathanw */
134 1.12.6.3 nathanw if (IS_BREAKPOINT_TRAP(type, 0)) {
135 1.12.6.3 nathanw int bkpt;
136 1.12.6.3 nathanw db_read_bytes(PC_REGS(DDB_REGS),BKPT_SIZE,(void *)&bkpt);
137 1.12.6.3 nathanw if (bkpt== BKPT_INST) {
138 1.12.6.3 nathanw PC_REGS(DDB_REGS) += BKPT_SIZE;
139 1.12.6.3 nathanw }
140 1.12.6.3 nathanw }
141 1.12.6.2 nathanw
142 1.12.6.2 nathanw memcpy(frame->fixreg, DDB_REGS->r, 32 * sizeof(u_int32_t));
143 1.12.6.2 nathanw frame->srr0 = DDB_REGS->iar;
144 1.12.6.2 nathanw frame->srr1 = DDB_REGS->msr;
145 1.12.6.2 nathanw frame->lr = DDB_REGS->lr;
146 1.12.6.2 nathanw frame->ctr = DDB_REGS->ctr;
147 1.12.6.2 nathanw frame->cr = DDB_REGS->cr;
148 1.12.6.2 nathanw frame->xer = DDB_REGS->xer;
149 1.12.6.2 nathanw #ifdef PPC_IBM4XX
150 1.12.6.2 nathanw frame->dear = DDB_REGS->dear;
151 1.12.6.2 nathanw frame->esr = DDB_REGS->esr;
152 1.12.6.2 nathanw frame->pid = DDB_REGS->pid;
153 1.12.6.2 nathanw #endif
154 1.12.6.2 nathanw
155 1.12.6.2 nathanw return 1;
156 1.12.6.2 nathanw }
157 1.12.6.2 nathanw
158 1.12.6.2 nathanw #ifdef PPC_IBM4XX
159 1.12.6.2 nathanw const struct db_command db_machine_command_table[] = {
160 1.12.6.2 nathanw { "ctx", db_ppc4xx_ctx, 0, 0 },
161 1.12.6.2 nathanw { "pv", db_ppc4xx_pv, 0, 0 },
162 1.12.6.2 nathanw { "reset", db_ppc4xx_reset, 0, 0 },
163 1.12.6.2 nathanw { "tf", db_ppc4xx_tf, 0, 0 },
164 1.12.6.2 nathanw { "tlb", db_ppc4xx_dumptlb, 0, 0 },
165 1.12.6.2 nathanw #ifdef USERACC
166 1.12.6.2 nathanw { "user", db_ppc4xx_useracc, 0, 0 },
167 1.12.6.2 nathanw #endif
168 1.12.6.2 nathanw { NULL, }
169 1.12.6.2 nathanw };
170 1.12.6.2 nathanw
171 1.12.6.2 nathanw static void
172 1.12.6.2 nathanw db_ppc4xx_ctx(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
173 1.12.6.2 nathanw {
174 1.12.6.2 nathanw struct proc *p;
175 1.12.6.2 nathanw
176 1.12.6.2 nathanw /* XXX LOCKING XXX */
177 1.12.6.2 nathanw for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) {
178 1.12.6.2 nathanw if (p->p_stat) {
179 1.12.6.2 nathanw db_printf("process %p:", p);
180 1.12.6.2 nathanw db_printf("pid:%d pmap:%p ctx:%d %s\n",
181 1.12.6.2 nathanw p->p_pid, p->p_vmspace->vm_map.pmap,
182 1.12.6.2 nathanw p->p_vmspace->vm_map.pmap->pm_ctx,
183 1.12.6.2 nathanw p->p_comm);
184 1.12.6.2 nathanw }
185 1.12.6.2 nathanw }
186 1.12.6.2 nathanw return;
187 1.12.6.2 nathanw }
188 1.12.6.2 nathanw
189 1.12.6.2 nathanw static void
190 1.12.6.2 nathanw db_ppc4xx_pv(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
191 1.12.6.2 nathanw {
192 1.12.6.2 nathanw struct pv_entry {
193 1.12.6.2 nathanw struct pv_entry *pv_next; /* Linked list of mappings */
194 1.12.6.2 nathanw vaddr_t pv_va; /* virtual address of mapping */
195 1.12.6.2 nathanw struct pmap *pv_pm;
196 1.12.6.2 nathanw };
197 1.12.6.2 nathanw struct pv_entry *pa_to_pv(paddr_t);
198 1.12.6.2 nathanw struct pv_entry *pv;
199 1.12.6.2 nathanw
200 1.12.6.2 nathanw if (!have_addr) {
201 1.12.6.2 nathanw db_printf("pv: <pa>\n");
202 1.12.6.2 nathanw return;
203 1.12.6.2 nathanw }
204 1.12.6.2 nathanw pv = pa_to_pv(addr);
205 1.12.6.2 nathanw db_printf("pv at %p\n", pv);
206 1.12.6.2 nathanw while (pv && pv->pv_pm) {
207 1.12.6.2 nathanw db_printf("next %p va %p pmap %p\n", pv->pv_next,
208 1.12.6.2 nathanw (void *)pv->pv_va, pv->pv_pm);
209 1.12.6.2 nathanw pv = pv->pv_next;
210 1.12.6.2 nathanw }
211 1.12.6.2 nathanw }
212 1.12.6.2 nathanw
213 1.12.6.2 nathanw static void
214 1.12.6.2 nathanw db_ppc4xx_reset(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
215 1.12.6.2 nathanw {
216 1.12.6.2 nathanw printf("Reseting...\n");
217 1.12.6.2 nathanw ppc4xx_reset();
218 1.12.6.2 nathanw }
219 1.12.6.2 nathanw
220 1.12.6.2 nathanw static void
221 1.12.6.2 nathanw db_ppc4xx_tf(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
222 1.12.6.2 nathanw {
223 1.12.6.2 nathanw struct trapframe *f;
224 1.12.6.2 nathanw
225 1.12.6.2 nathanw
226 1.12.6.2 nathanw if (have_addr) {
227 1.12.6.2 nathanw f = (struct trapframe *)addr;
228 1.12.6.2 nathanw
229 1.12.6.2 nathanw db_printf("r0-r3: \t%8.8x %8.8x %8.8x %8.8x\n",
230 1.12.6.2 nathanw f->fixreg[0], f->fixreg[1],
231 1.12.6.2 nathanw f->fixreg[2], f->fixreg[3]);
232 1.12.6.2 nathanw db_printf("r4-r7: \t%8.8x %8.8x %8.8x %8.8x\n",
233 1.12.6.2 nathanw f->fixreg[4], f->fixreg[5],
234 1.12.6.2 nathanw f->fixreg[6], f->fixreg[7]);
235 1.12.6.2 nathanw db_printf("r8-r11: \t%8.8x %8.8x %8.8x %8.8x\n",
236 1.12.6.2 nathanw f->fixreg[8], f->fixreg[9],
237 1.12.6.2 nathanw f->fixreg[10], f->fixreg[11]);
238 1.12.6.2 nathanw db_printf("r12-r15:\t%8.8x %8.8x %8.8x %8.8x\n",
239 1.12.6.2 nathanw f->fixreg[12], f->fixreg[13],
240 1.12.6.2 nathanw f->fixreg[14], f->fixreg[15]);
241 1.12.6.2 nathanw db_printf("r16-r19:\t%8.8x %8.8x %8.8x %8.8x\n",
242 1.12.6.2 nathanw f->fixreg[16], f->fixreg[17],
243 1.12.6.2 nathanw f->fixreg[18], f->fixreg[19]);
244 1.12.6.2 nathanw db_printf("r20-r23:\t%8.8x %8.8x %8.8x %8.8x\n",
245 1.12.6.2 nathanw f->fixreg[20], f->fixreg[21],
246 1.12.6.2 nathanw f->fixreg[22], f->fixreg[23]);
247 1.12.6.2 nathanw db_printf("r24-r27:\t%8.8x %8.8x %8.8x %8.8x\n",
248 1.12.6.2 nathanw f->fixreg[24], f->fixreg[25],
249 1.12.6.2 nathanw f->fixreg[26], f->fixreg[27]);
250 1.12.6.2 nathanw db_printf("r28-r31:\t%8.8x %8.8x %8.8x %8.8x\n",
251 1.12.6.2 nathanw f->fixreg[28], f->fixreg[29],
252 1.12.6.2 nathanw f->fixreg[30], f->fixreg[31]);
253 1.12.6.2 nathanw
254 1.12.6.2 nathanw db_printf("lr: %8.8x cr: %8.8x xer: %8.8x ctr: %8.8x\n",
255 1.12.6.2 nathanw f->lr, f->cr, f->xer, f->ctr);
256 1.12.6.2 nathanw db_printf("srr0(pc): %8.8x srr1(msr): %8.8x "
257 1.12.6.2 nathanw "dear: %8.8x esr: %8.8x\n",
258 1.12.6.2 nathanw f->srr0, f->srr1, f->dear, f->esr);
259 1.12.6.2 nathanw db_printf("exc: %8.8x pid: %8.8x\n",
260 1.12.6.2 nathanw f->exc, f->pid);
261 1.12.6.2 nathanw }
262 1.12.6.2 nathanw return;
263 1.12.6.2 nathanw }
264 1.12.6.2 nathanw
265 1.12.6.2 nathanw static const char *const tlbsizes[] = {
266 1.12.6.2 nathanw "1kB",
267 1.12.6.2 nathanw "4kB",
268 1.12.6.2 nathanw "16kB",
269 1.12.6.2 nathanw "64kB",
270 1.12.6.2 nathanw "256kB",
271 1.12.6.2 nathanw "1MB",
272 1.12.6.2 nathanw "4MB",
273 1.12.6.2 nathanw "16MB"
274 1.12.6.2 nathanw };
275 1.12.6.2 nathanw
276 1.12.6.2 nathanw static void
277 1.12.6.2 nathanw db_ppc4xx_dumptlb(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
278 1.12.6.2 nathanw {
279 1.12.6.2 nathanw int i, zone, tlbsize;
280 1.12.6.2 nathanw u_int zpr, pid, opid, msr;
281 1.12.6.2 nathanw u_long tlblo, tlbhi, tlbmask;
282 1.12.6.2 nathanw
283 1.12.6.2 nathanw zpr = mfspr(SPR_ZPR);
284 1.12.6.2 nathanw for (i = 0; i < NTLB; i++) {
285 1.12.6.2 nathanw asm volatile("mfmsr %3;"
286 1.12.6.2 nathanw "mfpid %4;"
287 1.12.6.2 nathanw "li %0,0;"
288 1.12.6.2 nathanw "mtmsr %0;"
289 1.12.6.2 nathanw "sync; isync;"
290 1.12.6.6 thorpej "tlbrelo %0,%5;"
291 1.12.6.6 thorpej "tlbrehi %1,%5;"
292 1.12.6.2 nathanw "mfpid %2;"
293 1.12.6.2 nathanw "mtpid %4;"
294 1.12.6.2 nathanw "mtmsr %3;"
295 1.12.6.2 nathanw "sync; isync"
296 1.12.6.2 nathanw : "=&r" (tlblo), "=&r" (tlbhi), "=r" (pid),
297 1.12.6.2 nathanw "=&r" (msr), "=&r" (opid) : "r" (i));
298 1.12.6.2 nathanw
299 1.12.6.2 nathanw if (strchr(modif, 'v') && !(tlbhi & TLB_VALID))
300 1.12.6.2 nathanw continue;
301 1.12.6.2 nathanw
302 1.12.6.2 nathanw tlbsize = (tlbhi & TLB_SIZE_MASK) >> TLB_SIZE_SHFT;
303 1.12.6.2 nathanw /* map tlbsize 0 .. 7 to masks for 1kB .. 16MB */
304 1.12.6.2 nathanw tlbmask = ~(1 << (tlbsize * 2 + 10)) + 1;
305 1.12.6.2 nathanw
306 1.12.6.2 nathanw if (have_addr && ((tlbhi & tlbmask) != (addr & tlbmask)))
307 1.12.6.2 nathanw continue;
308 1.12.6.2 nathanw
309 1.12.6.2 nathanw zone = (tlblo & TLB_ZSEL_MASK) >> TLB_ZSEL_SHFT;
310 1.12.6.2 nathanw db_printf("tlb%c%2d", tlbhi & TLB_VALID ? ' ' : '*', i);
311 1.12.6.2 nathanw db_printf(" PID %3d EPN 0x%08lx %-5s",
312 1.12.6.2 nathanw pid,
313 1.12.6.2 nathanw tlbhi & tlbmask,
314 1.12.6.2 nathanw tlbsizes[tlbsize]);
315 1.12.6.2 nathanw db_printf(" RPN 0x%08lx ZONE %2d%c %s %s %c%c%c%c%c %s",
316 1.12.6.2 nathanw tlblo & tlbmask,
317 1.12.6.2 nathanw zone,
318 1.12.6.2 nathanw "NTTA"[(zpr >> ((15 - zone) * 2)) & 3],
319 1.12.6.2 nathanw tlblo & TLB_EX ? "EX" : " ",
320 1.12.6.2 nathanw tlblo & TLB_WR ? "WR" : " ",
321 1.12.6.2 nathanw tlblo & TLB_W ? 'W' : ' ',
322 1.12.6.2 nathanw tlblo & TLB_I ? 'I' : ' ',
323 1.12.6.2 nathanw tlblo & TLB_M ? 'M' : ' ',
324 1.12.6.2 nathanw tlblo & TLB_G ? 'G' : ' ',
325 1.12.6.2 nathanw tlbhi & TLB_ENDIAN ? 'E' : ' ',
326 1.12.6.2 nathanw tlbhi & TLB_U0 ? "U0" : " ");
327 1.12.6.2 nathanw db_printf("\n");
328 1.12.6.2 nathanw }
329 1.12.6.2 nathanw }
330 1.12.6.2 nathanw
331 1.12.6.2 nathanw #ifdef USERACC
332 1.12.6.2 nathanw static void
333 1.12.6.2 nathanw db_ppc4xx_useracc(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
334 1.12.6.2 nathanw {
335 1.12.6.2 nathanw static paddr_t oldaddr = -1;
336 1.12.6.2 nathanw int instr = 0;
337 1.12.6.2 nathanw int data;
338 1.12.6.2 nathanw extern vaddr_t opc_disasm(vaddr_t loc, int);
339 1.12.6.2 nathanw
340 1.12.6.2 nathanw
341 1.12.6.2 nathanw if (!have_addr) {
342 1.12.6.2 nathanw addr = oldaddr;
343 1.12.6.2 nathanw }
344 1.12.6.2 nathanw if (addr == -1) {
345 1.12.6.2 nathanw db_printf("no address\n");
346 1.12.6.2 nathanw return;
347 1.12.6.2 nathanw }
348 1.12.6.2 nathanw addr &= ~0x3; /* align */
349 1.12.6.2 nathanw {
350 1.12.6.2 nathanw register char c, *cp = modif;
351 1.12.6.2 nathanw while ((c = *cp++) != 0)
352 1.12.6.2 nathanw if (c == 'i')
353 1.12.6.2 nathanw instr = 1;
354 1.12.6.2 nathanw }
355 1.12.6.2 nathanw while (count--) {
356 1.12.6.2 nathanw if (db_print_position() == 0) {
357 1.12.6.2 nathanw /* Always print the address. */
358 1.12.6.2 nathanw db_printf("%8.4lx:\t", addr);
359 1.12.6.2 nathanw }
360 1.12.6.2 nathanw oldaddr=addr;
361 1.12.6.2 nathanw copyin((void *)addr, &data, sizeof(data));
362 1.12.6.2 nathanw if (instr) {
363 1.12.6.2 nathanw opc_disasm(addr, data);
364 1.12.6.2 nathanw } else {
365 1.12.6.2 nathanw db_printf("%4.4x\n", data);
366 1.12.6.2 nathanw }
367 1.12.6.2 nathanw addr += 4;
368 1.12.6.2 nathanw db_end_line();
369 1.12.6.2 nathanw }
370 1.12.6.2 nathanw
371 1.12.6.2 nathanw }
372 1.12.6.2 nathanw #endif
373 1.12.6.2 nathanw
374 1.12.6.2 nathanw #endif /* PPC_IBM4XX */
375