]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ppc/db_interface.c
xnu-792.13.8.tar.gz
[apple/xnu.git] / osfmk / ppc / db_interface.c
1 /*
2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
14 * agreement.
15 *
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
18 * file.
19 *
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
27 *
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
29 */
30 /*
31 * @OSF_COPYRIGHT@
32 */
33
34 #include <platforms.h>
35 #include <time_stamp.h>
36 #include <mach_mp_debug.h>
37 #include <mach_ldebug.h>
38 #include <db_machine_commands.h>
39
40 #include <kern/spl.h>
41 #include <kern/cpu_number.h>
42 #include <kern/kern_types.h>
43 #include <kern/misc_protos.h>
44 #include <vm/pmap.h>
45
46 #include <ppc/mem.h>
47 #include <ppc/db_machdep.h>
48 #include <ppc/trap.h>
49 #include <ppc/setjmp.h>
50 #include <ppc/pmap.h>
51 #include <ppc/misc_protos.h>
52 #include <ppc/cpu_internal.h>
53 #include <ppc/exception.h>
54 #include <ppc/db_machdep.h>
55 #include <ppc/mappings.h>
56 #include <ppc/Firmware.h>
57
58 #include <mach/vm_param.h>
59 #include <mach/machine/vm_types.h>
60 #include <vm/vm_map.h>
61 #include <kern/thread.h>
62 #include <kern/task.h>
63 #include <kern/debug.h>
64 #include <pexpert/pexpert.h>
65 #include <IOKit/IOPlatformExpert.h>
66
67 #include <ddb/db_command.h>
68 #include <ddb/db_task_thread.h>
69 #include <ddb/db_run.h>
70 #include <ddb/db_trap.h>
71 #include <ddb/db_output.h>
72 #include <ddb/db_access.h>
73 #include <ddb/db_sym.h>
74 #include <ddb/db_break.h>
75 #include <ddb/db_watch.h>
76
77 struct savearea *ppc_last_saved_statep;
78 struct savearea ppc_nested_saved_state;
79 unsigned ppc_last_kdb_sp;
80
81 extern int debugger_cpu; /* Current cpu running debugger */
82
83 int db_all_set_up = 0;
84
85
86 #if !MACH_KDP
87 void kdp_register_send_receive(void);
88 #endif
89
90 /*
91 * Enter KDB through a keyboard trap.
92 * We show the registers as of the keyboard interrupt
93 * instead of those at its call to KDB.
94 */
95 struct int_regs {
96 /* XXX more registers ? */
97 struct ppc_interrupt_state *is;
98 };
99
100 extern char * trap_type[];
101 extern int TRAP_TYPES;
102
103 /*
104 * Code used to synchronize kdb among all cpus, one active at a time, switch
105 * from on to another using kdb_on! #cpu or cpu #cpu
106 */
107
108 decl_simple_lock_data(, kdb_lock) /* kdb lock */
109
110 #define db_simple_lock_init(l, e) hw_lock_init(&((l)->interlock))
111 #define db_simple_lock_try(l) hw_lock_try(&((l)->interlock))
112 #define db_simple_unlock(l) hw_lock_unlock(&((l)->interlock))
113
114 extern volatile unsigned int cpus_holding_bkpts; /* counter for number of cpus holding
115 breakpoints (ie: cpus that did not
116 insert back breakpoints) */
117 extern boolean_t db_breakpoints_inserted;
118
119 /* Forward */
120
121 extern void kdbprinttrap(
122 int type,
123 int code,
124 int *pc,
125 int sp);
126 extern void db_write_bytes_user_space(
127 vm_offset_t addr,
128 int size,
129 char *data,
130 task_t task);
131 extern int db_search_null(
132 task_t task,
133 unsigned *svaddr,
134 unsigned evaddr,
135 unsigned *skaddr,
136 int flag);
137 extern int kdb_enter(int);
138 extern void kdb_leave(void);
139 extern void lock_kdb(void);
140 extern void unlock_kdb(void);
141
142 #if DB_MACHINE_COMMANDS
143 struct db_command ppc_db_commands[] = {
144 { "lt", db_low_trace, CS_MORE|CS_SET_DOT, 0 },
145 { (char *)0, 0, 0, 0 }
146 };
147 #endif /* DB_MACHINE_COMMANDS */
148
149 #if !MACH_KDP
150 void kdp_register_send_receive(void) {}
151 #endif
152
153 extern jmp_buf_t *db_recover;
154
155 /*
156 * kdb_trap - field a TRACE or BPT trap
157 */
158 void
159 kdb_trap(
160 int type,
161 struct savearea *regs)
162 {
163 boolean_t trap_from_user;
164 int previous_console_device;
165 int code=0;
166
167 previous_console_device=switch_to_serial_console();
168
169 switch (type) {
170 case T_TRACE: /* single_step */
171 case T_PROGRAM: /* breakpoint */
172 #if 0
173 case T_WATCHPOINT: /* watchpoint */
174 #endif
175 case -1: /* keyboard interrupt */
176 break;
177
178 default:
179 if (db_recover) {
180 ppc_nested_saved_state = *regs;
181 db_printf("Caught ");
182 if (type > TRAP_TYPES)
183 db_printf("type %d", type);
184 else
185 db_printf("%s", trap_type[type]);
186 db_printf(" trap, pc = %llx\n",
187 regs->save_srr0);
188 db_error("");
189 /*NOTREACHED*/
190 }
191 kdbprinttrap(type, code, (int *)&regs->save_srr0, regs->save_r1);
192 }
193
194 getPerProc()->db_saved_state = regs;
195
196 ppc_last_saved_statep = regs;
197 ppc_last_kdb_sp = (unsigned) &type;
198
199 if (!IS_USER_TRAP(regs)) {
200 bzero((char *)&ddb_regs, sizeof (ddb_regs));
201 ddb_regs = *regs;
202 trap_from_user = FALSE;
203
204 }
205 else {
206 ddb_regs = *regs;
207 trap_from_user = TRUE;
208 }
209
210 db_task_trap(type, code, trap_from_user);
211
212 *regs = ddb_regs;
213
214 if ((type == T_PROGRAM) &&
215 (db_get_task_value(regs->save_srr0,
216 BKPT_SIZE,
217 FALSE,
218 db_target_space(current_thread(),
219 trap_from_user))
220 == BKPT_INST))
221 regs->save_srr0 += BKPT_SIZE;
222
223 kdb_exit:
224 getPerProc()->db_saved_state = 0;
225 switch_to_old_console(previous_console_device);
226
227 }
228
229
230 /*
231 * Print trap reason.
232 */
233
234 void
235 kdbprinttrap(
236 int type,
237 int code,
238 int *pc,
239 int sp)
240 {
241 printf("kernel: ");
242 if (type > TRAP_TYPES)
243 db_printf("type %d", type);
244 else
245 db_printf("%s", trap_type[type]);
246 db_printf(" trap, code=%x pc@%x = %x sp=%x\n",
247 code, pc, *(int *)pc, sp);
248 db_run_mode = STEP_CONTINUE;
249 }
250
251 /*
252 *
253 */
254 addr64_t db_vtophys(
255 pmap_t pmap,
256 vm_offset_t va)
257 {
258 ppnum_t pp;
259 addr64_t pa;
260
261 pp = pmap_find_phys(pmap, (addr64_t)va);
262
263 if (pp == 0) return(0); /* Couldn't find it */
264
265 pa = ((addr64_t)pp << 12) | (addr64_t)(va & 0xFFF); /* Get physical address */
266
267 return(pa);
268 }
269
270 /*
271 * Read bytes from task address space for debugger.
272 */
273 void
274 db_read_bytes(
275 vm_offset_t addr,
276 int size,
277 char *data,
278 task_t task)
279 {
280 int n,max;
281 addr64_t phys_dst;
282 addr64_t phys_src;
283 pmap_t pmap;
284
285 while (size > 0) {
286 if (task != NULL)
287 pmap = task->map->pmap;
288 else
289 pmap = kernel_pmap;
290
291 phys_src = db_vtophys(pmap, (vm_offset_t)addr);
292 if (phys_src == 0) {
293 db_printf("\nno memory is assigned to src address %08x\n",
294 addr);
295 db_error(0);
296 /* NOTREACHED */
297 }
298
299 phys_dst = db_vtophys(kernel_pmap, (vm_offset_t)data);
300 if (phys_dst == 0) {
301 db_printf("\nno memory is assigned to dst address %08x\n",
302 data);
303 db_error(0);
304 /* NOTREACHED */
305 }
306
307 /* don't over-run any page boundaries - check src range */
308 max = round_page_64(phys_src + 1) - phys_src;
309 if (max > size)
310 max = size;
311 /* Check destination won't run over boundary either */
312 n = round_page_64(phys_dst + 1) - phys_dst;
313
314 if (n < max) max = n;
315 size -= max;
316 addr += max;
317 phys_copy(phys_src, phys_dst, max);
318
319 /* resync I+D caches */
320 sync_cache64(phys_dst, max);
321
322 phys_src += max;
323 phys_dst += max;
324 }
325 }
326
327 /*
328 * Write bytes to task address space for debugger.
329 */
330 void
331 db_write_bytes(
332 vm_offset_t addr,
333 int size,
334 char *data,
335 task_t task)
336 {
337 int n,max;
338 addr64_t phys_dst;
339 addr64_t phys_src;
340 pmap_t pmap;
341
342 while (size > 0) {
343
344 phys_src = db_vtophys(kernel_pmap, (vm_offset_t)data);
345 if (phys_src == 0) {
346 db_printf("\nno memory is assigned to src address %08x\n",
347 data);
348 db_error(0);
349 /* NOTREACHED */
350 }
351
352 /* space stays as kernel space unless in another task */
353 if (task == NULL) pmap = kernel_pmap;
354 else pmap = task->map->pmap;
355
356 phys_dst = db_vtophys(pmap, (vm_offset_t)addr);
357 if (phys_dst == 0) {
358 db_printf("\nno memory is assigned to dst address %08x\n",
359 addr);
360 db_error(0);
361 /* NOTREACHED */
362 }
363
364 /* don't over-run any page boundaries - check src range */
365 max = round_page_64(phys_src + 1) - phys_src;
366 if (max > size)
367 max = size;
368 /* Check destination won't run over boundary either */
369 n = round_page_64(phys_dst + 1) - phys_dst;
370 if (n < max)
371 max = n;
372 size -= max;
373 addr += max;
374 phys_copy(phys_src, phys_dst, max);
375
376 /* resync I+D caches */
377 sync_cache64(phys_dst, max);
378
379 phys_src += max;
380 phys_dst += max;
381 }
382 }
383
384 boolean_t
385 db_check_access(
386 vm_offset_t addr,
387 int size,
388 task_t task)
389 {
390 register int n;
391 unsigned int kern_addr;
392
393 if (task == kernel_task || task == TASK_NULL) {
394 if (kernel_task == TASK_NULL) return(TRUE);
395 task = kernel_task;
396 } else if (task == TASK_NULL) {
397 if (current_thread() == THR_ACT_NULL) return(FALSE);
398 task = current_thread()->task;
399 }
400
401 while (size > 0) {
402 if(!pmap_find_phys(task->map->pmap, (addr64_t)addr)) return (FALSE); /* Fail if page not mapped */
403 n = trunc_page_32(addr+PPC_PGBYTES) - addr;
404 if (n > size)
405 n = size;
406 size -= n;
407 addr += n;
408 }
409 return(TRUE);
410 }
411
412 boolean_t
413 db_phys_eq(
414 task_t task1,
415 vm_offset_t addr1,
416 task_t task2,
417 vm_offset_t addr2)
418 {
419 addr64_t physa, physb;
420
421 if ((addr1 & (PPC_PGBYTES-1)) != (addr2 & (PPC_PGBYTES-1))) /* Is byte displacement the same? */
422 return FALSE;
423
424 if (task1 == TASK_NULL) { /* See if there is a task active */
425 if (current_thread() == THR_ACT_NULL) /* See if there is a current task */
426 return FALSE;
427 task1 = current_thread()->task; /* If so, use that one */
428 }
429
430 if(!(physa = db_vtophys(task1->map->pmap, (vm_offset_t)trunc_page_32(addr1)))) return FALSE; /* Get real address of the first */
431 if(!(physb = db_vtophys(task2->map->pmap, (vm_offset_t)trunc_page_32(addr2)))) return FALSE; /* Get real address of the second */
432
433 return (physa == physb); /* Check if they are equal, then return... */
434 }
435
436 #define DB_USER_STACK_ADDR (0xc0000000)
437 #define DB_NAME_SEARCH_LIMIT (DB_USER_STACK_ADDR-(PPC_PGBYTES*3))
438
439 boolean_t db_phys_cmp(
440 vm_offset_t a1,
441 vm_offset_t a2,
442 vm_size_t s1) {
443
444 db_printf("db_phys_cmp: not implemented\n");
445 return 0;
446 }
447
448
449 int
450 db_search_null(
451 task_t task,
452 unsigned *svaddr,
453 unsigned evaddr,
454 unsigned *skaddr,
455 int flag)
456 {
457 register unsigned vaddr;
458 register unsigned *kaddr;
459
460 db_printf("db_search_null: not implemented\n");
461
462 return(-1);
463 }
464
465 unsigned char *getProcName(struct proc *proc);
466
467 void
468 db_task_name(
469 task_t task)
470 {
471 register unsigned char *p;
472 register int n;
473 unsigned int vaddr, kaddr;
474 unsigned char tname[33];
475 int i;
476
477 p = 0;
478 tname[0] = 0;
479
480 if(task->bsd_info) p = getProcName((struct proc *)(task->bsd_info)); /* Point to task name */
481
482 if(p) {
483 for(i = 0; i < 32; i++) { /* Move no more than 32 bytes */
484 tname[i] = p[i];
485 if(p[i] == 0) break;
486 }
487 tname[i] = 0;
488 db_printf("%s", tname);
489 }
490 else db_printf("no name");
491 }
492
493 void
494 db_machdep_init(void) {
495 #define KDB_READY 0x1
496 extern int kdb_flag;
497
498 kdb_flag |= KDB_READY;
499 }
500
501
502 #ifdef __STDC__
503 #define KDB_SAVE(type, name) extern type name; type name##_save = name
504 #define KDB_RESTORE(name) name = name##_save
505 #else /* __STDC__ */
506 #define KDB_SAVE(type, name) extern type name; type name/**/_save = name
507 #define KDB_RESTORE(name) name = name/**/_save
508 #endif /* __STDC__ */
509
510 #define KDB_SAVE_CTXT() \
511 KDB_SAVE(int, db_run_mode); \
512 KDB_SAVE(boolean_t, db_sstep_print); \
513 KDB_SAVE(int, db_loop_count); \
514 KDB_SAVE(int, db_call_depth); \
515 KDB_SAVE(int, db_inst_count); \
516 KDB_SAVE(int, db_last_inst_count); \
517 KDB_SAVE(int, db_load_count); \
518 KDB_SAVE(int, db_store_count); \
519 KDB_SAVE(boolean_t, db_cmd_loop_done); \
520 KDB_SAVE(jmp_buf_t *, db_recover); \
521 KDB_SAVE(db_addr_t, db_dot); \
522 KDB_SAVE(db_addr_t, db_last_addr); \
523 KDB_SAVE(db_addr_t, db_prev); \
524 KDB_SAVE(db_addr_t, db_next); \
525 KDB_SAVE(db_regs_t, ddb_regs);
526
527 #define KDB_RESTORE_CTXT() \
528 KDB_RESTORE(db_run_mode); \
529 KDB_RESTORE(db_sstep_print); \
530 KDB_RESTORE(db_loop_count); \
531 KDB_RESTORE(db_call_depth); \
532 KDB_RESTORE(db_inst_count); \
533 KDB_RESTORE(db_last_inst_count); \
534 KDB_RESTORE(db_load_count); \
535 KDB_RESTORE(db_store_count); \
536 KDB_RESTORE(db_cmd_loop_done); \
537 KDB_RESTORE(db_recover); \
538 KDB_RESTORE(db_dot); \
539 KDB_RESTORE(db_last_addr); \
540 KDB_RESTORE(db_prev); \
541 KDB_RESTORE(db_next); \
542 KDB_RESTORE(ddb_regs);
543
544 /*
545 * switch to another cpu
546 */
547 void
548 kdb_on(
549 int cpu)
550 {
551 KDB_SAVE_CTXT();
552 if (cpu < 0 || cpu >= real_ncpus || !PerProcTable[cpu].ppe_vaddr->debugger_active)
553 return;
554 db_set_breakpoints();
555 db_set_watchpoints();
556 debugger_cpu = cpu;
557 unlock_debugger();
558 lock_debugger();
559 db_clear_breakpoints();
560 db_clear_watchpoints();
561 KDB_RESTORE_CTXT();
562 if (debugger_cpu == -1) {/* someone continued */
563 debugger_cpu = cpu_number();
564 db_continue_cmd(0, 0, 0, "");
565 }
566 }
567
568 /*
569 * system reboot
570 */
571
572 extern int (*PE_halt_restart)(unsigned int type);
573
574 void db_reboot(
575 db_expr_t addr,
576 boolean_t have_addr,
577 db_expr_t count,
578 char *modif)
579 {
580 boolean_t reboot = TRUE;
581 char *cp, c;
582
583 cp = modif;
584 while ((c = *cp++) != 0) {
585 if (c == 'r') /* reboot */
586 reboot = TRUE;
587 if (c == 'h') /* halt */
588 reboot = FALSE;
589 }
590 if(!reboot) halt_all_cpus(FALSE); /* If no reboot, try to be clean about it */
591
592 if (PE_halt_restart) return (*PE_halt_restart)(kPERestartCPU);
593 db_printf("Sorry, system can't reboot automatically yet... You need to do it by hand...\n");
594
595 }