]>
Commit | Line | Data |
---|---|---|
1c79356b A |
1 | /* |
2 | * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * The contents of this file constitute Original Code as defined in and | |
7 | * are subject to the Apple Public Source License Version 1.1 (the | |
8 | * "License"). You may not use this file except in compliance with the | |
9 | * License. Please obtain a copy of the License at | |
10 | * http://www.apple.com/publicsource and read it before using this file. | |
11 | * | |
12 | * This Original Code and all software distributed under the License are | |
13 | * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
14 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
15 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
16 | * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the | |
17 | * License for the specific language governing rights and limitations | |
18 | * under the License. | |
19 | * | |
20 | * @APPLE_LICENSE_HEADER_END@ | |
21 | */ | |
22 | /* | |
23 | * Copyright (c) 1997 Apple Computer, Inc. All rights reserved. | |
24 | * Copyright (c) 1994 NeXT Computer, Inc. All rights reserved. | |
25 | * | |
26 | * machdep/ppc/kdp_machdep.c | |
27 | * | |
28 | * Machine-dependent code for Remote Debugging Protocol | |
29 | * | |
30 | * March, 1997 Created. Umesh Vaishampayan [umeshv@NeXT.com] | |
31 | * | |
32 | */ | |
33 | ||
34 | #include <mach/mach_types.h> | |
35 | #include <mach/exception_types.h> | |
36 | #include <ppc/exception.h> | |
37 | #include <ppc/proc_reg.h> | |
38 | #include <kdp/kdp_internal.h> | |
39 | #include <ppc/savearea.h> | |
40 | #include <kern/debug.h> | |
41 | ||
42 | #define KDP_TEST_HARNESS 0 | |
43 | #if KDP_TEST_HARNESS | |
44 | #define dprintf(x) kprintf x | |
45 | #else | |
46 | #define dprintf(x) | |
47 | #endif | |
48 | ||
49 | void print_saved_state(void *); | |
50 | void kdp_call(void); | |
51 | void kdp_trap( unsigned int, struct ppc_thread_state *); | |
52 | int kdp_getc(void); | |
53 | boolean_t kdp_call_kdb(void); | |
54 | ||
55 | void | |
56 | kdp_exception( | |
57 | unsigned char *pkt, | |
58 | int *len, | |
59 | unsigned short *remote_port, | |
60 | unsigned int exception, | |
61 | unsigned int code, | |
62 | unsigned int subcode | |
63 | ) | |
64 | { | |
65 | struct { | |
66 | kdp_exception_t pkt; | |
67 | kdp_exc_info_t exc; | |
68 | } aligned_pkt; | |
69 | kdp_exception_t *rq = (kdp_exception_t *)&aligned_pkt; | |
70 | ||
71 | bcopy((char *)pkt, (char *)rq, sizeof(*rq)); | |
72 | rq->hdr.request = KDP_EXCEPTION; | |
73 | rq->hdr.is_reply = 0; | |
74 | rq->hdr.seq = kdp.exception_seq; | |
75 | rq->hdr.key = 0; | |
76 | rq->hdr.len = sizeof (*rq) + sizeof(kdp_exc_info_t); | |
77 | ||
78 | rq->n_exc_info = 1; | |
79 | rq->exc_info[0].cpu = 0; | |
80 | rq->exc_info[0].exception = exception; | |
81 | rq->exc_info[0].code = code; | |
82 | rq->exc_info[0].subcode = subcode; | |
83 | ||
84 | rq->hdr.len += rq->n_exc_info * sizeof (kdp_exc_info_t); | |
85 | ||
86 | bcopy((char *)rq, (char *)pkt, rq->hdr.len); | |
87 | ||
88 | kdp.exception_ack_needed = TRUE; | |
89 | ||
90 | *remote_port = kdp.exception_port; | |
91 | *len = rq->hdr.len; | |
92 | } | |
93 | ||
94 | boolean_t | |
95 | kdp_exception_ack( | |
96 | unsigned char *pkt, | |
97 | int len | |
98 | ) | |
99 | { | |
100 | kdp_exception_ack_t aligned_pkt; | |
101 | kdp_exception_ack_t *rq = (kdp_exception_ack_t *)&aligned_pkt; | |
102 | ||
103 | if (len < sizeof (*rq)) | |
104 | return(FALSE); | |
105 | ||
106 | bcopy((char *)pkt, (char *)rq, sizeof(*rq)); | |
107 | ||
108 | if (!rq->hdr.is_reply || rq->hdr.request != KDP_EXCEPTION) | |
109 | return(FALSE); | |
110 | ||
111 | dprintf(("kdp_exception_ack seq %x %x\n", rq->hdr.seq, kdp.exception_seq)); | |
112 | ||
113 | if (rq->hdr.seq == kdp.exception_seq) { | |
114 | kdp.exception_ack_needed = FALSE; | |
115 | kdp.exception_seq++; | |
116 | } | |
117 | return(TRUE); | |
118 | } | |
119 | ||
120 | static void | |
121 | kdp_getintegerstate( | |
122 | struct ppc_thread_state *state | |
123 | ) | |
124 | { | |
125 | struct ppc_thread_state *saved_state; | |
126 | ||
127 | saved_state = kdp.saved_state; | |
128 | ||
129 | bzero((char *)state,sizeof (struct ppc_thread_state)) ; | |
130 | ||
131 | state->srr0 = saved_state->srr0; | |
132 | state->srr1 = saved_state->srr1; | |
133 | state->r0 = saved_state->r0; | |
134 | state->r1 = saved_state->r1; | |
135 | state->r2 = saved_state->r2; | |
136 | state->r3 = saved_state->r3; | |
137 | state->r4 = saved_state->r4; | |
138 | state->r5 = saved_state->r5; | |
139 | state->r6 = saved_state->r6; | |
140 | state->r7 = saved_state->r7; | |
141 | state->r8 = saved_state->r8; | |
142 | state->r9 = saved_state->r9; | |
143 | state->r10 = saved_state->r10; | |
144 | state->r11 = saved_state->r11; | |
145 | state->r12 = saved_state->r12; | |
146 | state->r13 = saved_state->r13; | |
147 | state->r14 = saved_state->r14; | |
148 | state->r15 = saved_state->r15; | |
149 | state->r16 = saved_state->r16; | |
150 | state->r17 = saved_state->r17; | |
151 | state->r18 = saved_state->r18; | |
152 | state->r19 = saved_state->r19; | |
153 | state->r20 = saved_state->r20; | |
154 | state->r21 = saved_state->r21; | |
155 | state->r22 = saved_state->r22; | |
156 | state->r23 = saved_state->r23; | |
157 | state->r24 = saved_state->r24; | |
158 | state->r25 = saved_state->r25; | |
159 | state->r26 = saved_state->r26; | |
160 | state->r27 = saved_state->r27; | |
161 | state->r28 = saved_state->r28; | |
162 | state->r29 = saved_state->r29; | |
163 | state->r30 = saved_state->r30; | |
164 | state->r31 = saved_state->r31; | |
165 | state->cr = saved_state->cr; | |
166 | state->xer = saved_state->xer; | |
167 | state->lr = saved_state->lr; | |
168 | state->ctr = saved_state->ctr; | |
169 | state->mq = saved_state->mq; /* This is BOGUS ! (601) ONLY */ | |
170 | } | |
171 | ||
172 | kdp_error_t | |
173 | kdp_machine_read_regs( | |
174 | unsigned int cpu, | |
175 | unsigned int flavor, | |
176 | char *data, | |
177 | int *size | |
178 | ) | |
179 | { | |
180 | switch (flavor) { | |
181 | ||
182 | case PPC_THREAD_STATE: | |
183 | dprintf(("kdp_readregs THREAD_STATE\n")); | |
184 | kdp_getintegerstate((struct ppc_thread_state *)data); | |
185 | *size = PPC_THREAD_STATE_COUNT * sizeof(int); | |
186 | return KDPERR_NO_ERROR; | |
187 | ||
188 | case PPC_FLOAT_STATE: | |
189 | dprintf(("kdp_readregs THREAD_FPSTATE\n")); | |
190 | bzero((char *)data ,sizeof(struct ppc_float_state)); | |
191 | *size = PPC_FLOAT_STATE_COUNT * sizeof(int); | |
192 | return KDPERR_NO_ERROR; | |
193 | ||
194 | default: | |
195 | dprintf(("kdp_readregs bad flavor %d\n")); | |
196 | return KDPERR_BADFLAVOR; | |
197 | } | |
198 | } | |
199 | ||
200 | static void | |
201 | kdp_setintegerstate( | |
202 | struct ppc_thread_state *state | |
203 | ) | |
204 | { | |
205 | struct ppc_thread_state *saved_state; | |
206 | ||
207 | saved_state = kdp.saved_state; | |
208 | ||
209 | saved_state->srr0 = state->srr0; | |
210 | saved_state->srr1 = state->srr1; | |
211 | saved_state->r0 = state->r0; | |
212 | saved_state->r1 = state->r1; | |
213 | saved_state->r2 = state->r2; | |
214 | saved_state->r3 = state->r3; | |
215 | saved_state->r4 = state->r4; | |
216 | saved_state->r5 = state->r5; | |
217 | saved_state->r6 = state->r6; | |
218 | saved_state->r7 = state->r7; | |
219 | saved_state->r8 = state->r8; | |
220 | saved_state->r9 = state->r9; | |
221 | saved_state->r10 = state->r10; | |
222 | saved_state->r11 = state->r11; | |
223 | saved_state->r12 = state->r12; | |
224 | saved_state->r13 = state->r13; | |
225 | saved_state->r14 = state->r14; | |
226 | saved_state->r15 = state->r15; | |
227 | saved_state->r16 = state->r16; | |
228 | saved_state->r17 = state->r17; | |
229 | saved_state->r18 = state->r18; | |
230 | saved_state->r19 = state->r19; | |
231 | saved_state->r20 = state->r20; | |
232 | saved_state->r21 = state->r21; | |
233 | saved_state->r22 = state->r22; | |
234 | saved_state->r23 = state->r23; | |
235 | saved_state->r24 = state->r24; | |
236 | saved_state->r25 = state->r25; | |
237 | saved_state->r26 = state->r26; | |
238 | saved_state->r27 = state->r27; | |
239 | saved_state->r28 = state->r28; | |
240 | saved_state->r29 = state->r29; | |
241 | saved_state->r30 = state->r30; | |
242 | saved_state->r31 = state->r31; | |
243 | saved_state->cr = state->cr; | |
244 | saved_state->xer = state->xer; | |
245 | saved_state->lr = state->lr; | |
246 | saved_state->ctr = state->ctr; | |
247 | saved_state->mq = state->mq; /* BOGUS! (601)ONLY */ | |
248 | } | |
249 | ||
250 | kdp_error_t | |
251 | kdp_machine_write_regs( | |
252 | unsigned int cpu, | |
253 | unsigned int flavor, | |
254 | char *data, | |
255 | int *size | |
256 | ) | |
257 | { | |
258 | switch (flavor) { | |
259 | ||
260 | case PPC_THREAD_STATE: | |
261 | dprintf(("kdp_writeregs THREAD_STATE\n")); | |
262 | kdp_setintegerstate((struct ppc_thread_state *)data); | |
263 | ||
264 | #if KDP_TEST_HARNESS | |
265 | DumpTheSave((struct savearea *)data); /* (TEST/DEBUG) */ | |
266 | #endif | |
267 | return KDPERR_NO_ERROR; | |
268 | ||
269 | case PPC_FLOAT_STATE: | |
270 | dprintf(("kdp_writeregs THREAD_FPSTATE\n")); | |
271 | return KDPERR_NO_ERROR; | |
272 | ||
273 | default: | |
274 | dprintf(("kdp_writeregs bad flavor %d\n")); | |
275 | return KDPERR_BADFLAVOR; | |
276 | } | |
277 | } | |
278 | ||
279 | void | |
280 | kdp_machine_hostinfo( | |
281 | kdp_hostinfo_t *hostinfo | |
282 | ) | |
283 | { | |
284 | machine_slot_t m; | |
285 | int i; | |
286 | ||
287 | hostinfo->cpus_mask = 0; | |
288 | ||
289 | for (i = 0; i < machine_info.max_cpus; i++) { | |
290 | m = &machine_slot[i]; | |
291 | if (!m->is_cpu) | |
292 | continue; | |
293 | ||
294 | hostinfo->cpus_mask |= (1 << i); | |
295 | if (hostinfo->cpu_type == 0) { | |
296 | hostinfo->cpu_type = m->cpu_type; | |
297 | hostinfo->cpu_subtype = m->cpu_subtype; | |
298 | } | |
299 | } | |
300 | } | |
301 | ||
302 | void | |
303 | kdp_panic( | |
304 | const char *msg | |
305 | ) | |
306 | { | |
307 | printf("kdp panic: %s\n", msg); | |
308 | while(1) {} | |
309 | } | |
310 | ||
311 | ||
312 | void | |
313 | kdp_reboot(void) | |
314 | { | |
315 | halt_all_cpus(TRUE);; | |
316 | } | |
317 | ||
318 | int | |
319 | kdp_intr_disbl(void) | |
320 | { | |
321 | return (splhigh()); | |
322 | } | |
323 | ||
324 | void | |
325 | kdp_intr_enbl(int s) | |
326 | { | |
327 | splx(s); | |
328 | } | |
329 | ||
330 | void | |
331 | kdp_us_spin(int usec) | |
332 | { | |
333 | extern void delay(int); | |
334 | ||
335 | delay(usec/100); | |
336 | } | |
337 | ||
338 | void print_saved_state(void *state) | |
339 | { | |
340 | struct ppc_thread_state *saved_state; | |
341 | ||
342 | saved_state = state; | |
343 | ||
344 | printf("pc = 0x%x\n", saved_state->srr0); | |
345 | printf("msr = 0x%x\n", saved_state->srr1); | |
346 | printf("rp = 0x%x\n", saved_state->lr); | |
347 | printf("sp = 0x%x\n", saved_state->r1); | |
348 | ||
349 | } | |
350 | ||
351 | void | |
352 | kdp_call() | |
353 | { | |
354 | Debugger("inline call to debugger(machine_startup)"); | |
355 | } | |
356 | ||
357 | /* | |
358 | * table to convert system specific code to generic codes for kdb | |
359 | */ | |
360 | int kdp_trap_codes[] = { | |
361 | EXC_BAD_ACCESS, /* 0x0000 INVALID EXCEPTION */ | |
362 | EXC_BAD_ACCESS, /* 0x0100 System reset */ | |
363 | EXC_BAD_ACCESS, /* 0x0200 Machine check */ | |
364 | EXC_BAD_ACCESS, /* 0x0300 Data access */ | |
365 | EXC_BAD_ACCESS, /* 0x0400 Instruction access */ | |
366 | EXC_BAD_ACCESS, /* 0x0500 External interrupt */ | |
367 | EXC_BAD_ACCESS, /* 0x0600 Alignment */ | |
368 | EXC_BREAKPOINT, /* 0x0700 Program - fp exc, ill/priv instr, trap */ | |
369 | EXC_ARITHMETIC, /* 0x0800 Floating point disabled */ | |
370 | EXC_SOFTWARE, /* 0x0900 Decrementer */ | |
371 | EXC_BAD_ACCESS, /* 0x0A00 I/O controller interface */ | |
372 | EXC_BAD_ACCESS, /* 0x0B00 INVALID EXCEPTION */ | |
373 | EXC_SOFTWARE, /* 0x0C00 System call exception */ | |
374 | EXC_BREAKPOINT, /* 0x0D00 Trace */ | |
375 | EXC_SOFTWARE, /* 0x0E00 FP assist */ | |
376 | EXC_SOFTWARE, /* 0x0F00 Performance monitoring */ | |
377 | EXC_ARITHMETIC, /* 0x0F20 Altivec disabled */ | |
378 | EXC_BAD_ACCESS, /* 0x1000 Instruction PTE miss */ | |
379 | EXC_BAD_ACCESS, /* 0x1100 Data load PTE miss */ | |
380 | EXC_BAD_ACCESS, /* 0x1200 Data store PTE miss */ | |
381 | EXC_BREAKPOINT, /* 0x1300 Instruction bkpt */ | |
382 | EXC_SOFTWARE, /* 0x1400 System management */ | |
383 | EXC_BAD_ACCESS, /* 0x1500 INVALID EXCEPTION */ | |
384 | EXC_ARITHMETIC, /* 0x1600 Altivec Assist */ | |
385 | EXC_BAD_ACCESS, /* 0x1700 INVALID EXCEPTION */ | |
386 | EXC_BAD_ACCESS, /* 0x1800 INVALID EXCEPTION */ | |
387 | EXC_BAD_ACCESS, /* 0x1900 INVALID EXCEPTION */ | |
388 | EXC_BAD_ACCESS, /* 0x1A00 INVALID EXCEPTION */ | |
389 | EXC_BAD_ACCESS, /* 0x1B00 INVALID EXCEPTION */ | |
390 | EXC_BAD_ACCESS, /* 0x1C00 INVALID EXCEPTION */ | |
391 | EXC_BAD_ACCESS, /* 0x1D00 INVALID EXCEPTION */ | |
392 | EXC_BAD_ACCESS, /* 0x1E00 INVALID EXCEPTION */ | |
393 | EXC_BAD_ACCESS, /* 0x1F00 INVALID EXCEPTION */ | |
394 | EXC_BREAKPOINT, /* 0x2000 Run Mode/Trace */ | |
395 | EXC_BAD_ACCESS, /* 0x2100 INVALID EXCEPTION */ | |
396 | EXC_BAD_ACCESS, /* 0x2200 INVALID EXCEPTION */ | |
397 | EXC_BAD_ACCESS, /* 0x2300 INVALID EXCEPTION */ | |
398 | EXC_BAD_ACCESS, /* 0x2400 INVALID EXCEPTION */ | |
399 | EXC_BAD_ACCESS, /* 0x2500 INVALID EXCEPTION */ | |
400 | EXC_BAD_ACCESS, /* 0x2600 INVALID EXCEPTION */ | |
401 | EXC_BAD_ACCESS, /* 0x2700 INVALID EXCEPTION */ | |
402 | EXC_BAD_ACCESS, /* 0x2800 INVALID EXCEPTION */ | |
403 | EXC_BAD_ACCESS, /* 0x2900 INVALID EXCEPTION */ | |
404 | EXC_BAD_ACCESS, /* 0x2A00 INVALID EXCEPTION */ | |
405 | EXC_BAD_ACCESS, /* 0x2B00 INVALID EXCEPTION */ | |
406 | EXC_BAD_ACCESS, /* 0x2C00 INVALID EXCEPTION */ | |
407 | EXC_BAD_ACCESS, /* 0x2D00 INVALID EXCEPTION */ | |
408 | EXC_BAD_ACCESS, /* 0x2E00 INVALID EXCEPTION */ | |
409 | EXC_BAD_ACCESS, /* 0x2F00 INVALID EXCEPTION */ | |
410 | EXC_SOFTWARE /* 0x3000 AST trap (software) */ | |
411 | }; | |
412 | ||
413 | int | |
414 | kdp_getc() | |
415 | { | |
416 | return(cnmaygetc()); | |
417 | } | |
418 | ||
419 | int kdp_backtrace; | |
420 | int kdp_sr_dump; | |
421 | int kdp_dabr; | |
422 | int kdp_noisy; | |
423 | ||
424 | #define kdp_code(x) kdp_trap_codes[((x)==T_AST?0x31:(x)/T_VECTOR_SIZE)] | |
425 | ||
426 | void | |
427 | kdp_trap( | |
428 | unsigned int exception, | |
429 | struct ppc_thread_state *saved_state | |
430 | ) | |
431 | { | |
432 | unsigned int *fp; | |
433 | unsigned int register sp; | |
434 | struct ppc_thread_state *state; | |
435 | ||
436 | if (kdp_noisy) { | |
437 | if (kdp_backtrace) { | |
438 | printf("\nvector=%x, \n", exception/4); | |
439 | #ifdef XXX | |
440 | regDump(saved_state); | |
441 | #endif | |
442 | sp = saved_state->r1; | |
443 | printf("stack backtrace - sp(%x) ", sp); | |
444 | fp = (unsigned int *) *((unsigned int *)sp); | |
445 | while (fp) { | |
446 | printf("0x%08x ", fp[2]); | |
447 | fp = (unsigned int *)*fp; | |
448 | } | |
449 | printf("\n"); | |
450 | } | |
451 | #ifdef XXX | |
452 | if (kdp_sr_dump) { | |
453 | dump_segment_registers(); | |
454 | } | |
455 | #endif | |
456 | ||
457 | printf("vector=%d ", exception/4); | |
458 | } | |
459 | ||
460 | kdp_raise_exception(kdp_code(exception), 0, 0, saved_state); | |
461 | ||
462 | if (kdp_noisy) | |
463 | printf("kdp_trap: kdp_raise_exception() ret\n"); | |
464 | ||
465 | if (*((int *)saved_state->srr0) == 0x7c800008) | |
466 | saved_state->srr0 += 4; /* BKPT_SIZE */ | |
467 | ||
468 | if(saved_state->srr1 & (MASK(MSR_SE) | MASK(MSR_BE))) { /* Are we just stepping or continuing */ | |
469 | db_run_mode = STEP_ONCE; /* We are stepping */ | |
470 | } | |
471 | else db_run_mode = STEP_CONTINUE; /* Otherwise we are continuing */ | |
472 | ||
473 | ||
474 | #ifdef XXX | |
475 | mtspr(dabr, kdp_dabr); | |
476 | #endif | |
477 | } | |
478 | ||
479 | boolean_t | |
480 | kdp_call_kdb( | |
481 | void) | |
482 | { | |
483 | switch_debugger=1; | |
484 | return(TRUE); | |
485 | } | |
486 | ||
487 | void kdp_print_registers(struct ppc_saved_state *state) | |
488 | { | |
489 | int i; | |
490 | for (i=0; i<32; i++) { | |
491 | if ((i % 8) == 0) | |
492 | printf("\n%4d :",i); | |
493 | printf(" %08x",*(&state->r0+i)); | |
494 | } | |
495 | printf("\n"); | |
496 | printf("cr = 0x%08x\t\t",state->cr); | |
497 | printf("xer = 0x%08x\n",state->xer); | |
498 | printf("lr = 0x%08x\t\t",state->lr); | |
499 | printf("ctr = 0x%08x\n",state->ctr); | |
500 | printf("srr0(iar) = 0x%08x\t\t",state->srr0); | |
501 | printf("srr1(msr) = 0x%08B\n",state->srr1, | |
502 | "\x10\x11""EE\x12PR\x13""FP\x14ME\x15""FE0\x16SE\x18" | |
503 | "FE1\x19""AL\x1a""EP\x1bIT\x1c""DT"); | |
504 | printf("mq = 0x%08x\t\t",state->mq); | |
505 | printf("sr_copyin = 0x%08x\n",state->sr_copyin); | |
506 | printf("\n"); | |
507 | } | |
508 | ||
509 | void | |
510 | kdp_print_backtrace( | |
511 | unsigned int exception, | |
512 | struct ppc_saved_state *saved_state) | |
513 | { | |
514 | extern void kdp_print_registers(struct ppc_saved_state *); | |
515 | extern void print_backtrace(struct ppc_saved_state *); | |
516 | extern unsigned int debug_mode, disableDebugOuput; | |
517 | ||
518 | disableDebugOuput = FALSE; | |
519 | debug_mode = TRUE; | |
520 | printf("re-entering kdp:\n"); | |
521 | printf("vector=%x, \n", exception/4); | |
522 | kdp_print_registers(saved_state); | |
523 | print_backtrace(saved_state); | |
524 | printf("panic: We are hanging here...\n"); | |
525 | while(1); | |
526 | } |