]> git.saurik.com Git - apple/xnu.git/blame - osfmk/i386/db_interface.c
xnu-517.12.7.tar.gz
[apple/xnu.git] / osfmk / i386 / db_interface.c
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
e5568f75
A
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.
1c79356b 11 *
e5568f75
A
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
1c79356b
A
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
e5568f75
A
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.
1c79356b
A
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22/*
23 * @OSF_COPYRIGHT@
24 */
25/*
26 * Mach Operating System
27 * Copyright (c) 1991,1990 Carnegie Mellon University
28 * All Rights Reserved.
29 *
30 * Permission to use, copy, modify and distribute this software and its
31 * documentation is hereby granted, provided that both the copyright
32 * notice and this permission notice appear in all copies of the
33 * software, derivative works or modified versions, and any portions
34 * thereof, and that both notices appear in supporting documentation.
35 *
36 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
37 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
38 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
39 *
40 * Carnegie Mellon requests users of this software to return to
41 *
42 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
43 * School of Computer Science
44 * Carnegie Mellon University
45 * Pittsburgh PA 15213-3890
46 *
47 * any improvements or extensions that they make and grant Carnegie Mellon
48 * the rights to redistribute these changes.
49 */
50/*
51 */
52
53/*
54 * Interface to new debugger.
55 */
56#include <cpus.h>
57#include <platforms.h>
58#include <time_stamp.h>
59#include <mach_mp_debug.h>
60#include <mach_ldebug.h>
61#include <kern/spl.h>
62#include <kern/cpu_number.h>
63#include <kern/kern_types.h>
64#include <kern/misc_protos.h>
65#include <vm/pmap.h>
66
67#include <i386/thread.h>
68#include <i386/db_machdep.h>
69#include <i386/seg.h>
70#include <i386/trap.h>
71#include <i386/setjmp.h>
72#include <i386/pmap.h>
73#include <i386/misc_protos.h>
74
75#include <mach/vm_param.h>
76#include <vm/vm_map.h>
77#include <kern/thread.h>
78#include <kern/task.h>
79
80#include <ddb/db_command.h>
81#include <ddb/db_task_thread.h>
82#include <ddb/db_run.h>
83#include <ddb/db_trap.h>
84#include <ddb/db_output.h>
85#include <ddb/db_access.h>
86#include <ddb/db_sym.h>
87#include <ddb/db_break.h>
88#include <ddb/db_watch.h>
89
90int db_active = 0;
91int db_pass_thru[NCPUS];
92struct i386_saved_state *i386_last_saved_statep;
93struct i386_saved_state i386_nested_saved_state;
94unsigned i386_last_kdb_sp;
95
96vm_offset_t db_stacks[NCPUS];
97
98extern thread_act_t db_default_act;
99
100#if MACH_MP_DEBUG
101extern int masked_state_cnt[];
102#endif /* MACH_MP_DEBUG */
103
104/*
105 * Enter KDB through a keyboard trap.
106 * We show the registers as of the keyboard interrupt
107 * instead of those at its call to KDB.
108 */
109struct int_regs {
110 int gs;
111 int fs;
112 int edi;
113 int esi;
114 int ebp;
115 int ebx;
116 struct i386_interrupt_state *is;
117};
118
119extern char * trap_type[];
120extern int TRAP_TYPES;
121
122/* Forward */
123
124extern void kdbprinttrap(
125 int type,
126 int code,
127 int *pc,
128 int sp);
129extern void kdb_kentry(
130 struct int_regs *int_regs);
131extern int db_user_to_kernel_address(
132 task_t task,
133 vm_offset_t addr,
134 unsigned *kaddr,
135 int flag);
136extern void db_write_bytes_user_space(
137 vm_offset_t addr,
138 int size,
139 char *data,
140 task_t task);
141extern int db_search_null(
142 task_t task,
143 unsigned *svaddr,
144 unsigned evaddr,
145 unsigned *skaddr,
146 int flag);
147extern int kdb_enter(int);
148extern void kdb_leave(void);
149extern void lock_kdb(void);
150extern void unlock_kdb(void);
151
152/*
153 * kdb_trap - field a TRACE or BPT trap
154 */
155
156
157extern jmp_buf_t *db_recover;
158spl_t saved_ipl[NCPUS]; /* just to know what IPL was before trap */
159struct i386_saved_state *saved_state[NCPUS];
160
161/*
162 * Translate the state saved in a task state segment into an
163 * exception frame. Since we "know" we always want the state
164 * in a ktss, we hard-wire that in, rather than indexing the gdt
165 * with tss_sel to derive a pointer to the desired tss.
166 */
167void
168db_tss_to_frame(
169 int tss_sel,
170 struct i386_saved_state *regs)
171{
172 extern struct i386_tss ktss;
173 int mycpu = cpu_number();
174 struct i386_tss *tss;
175
176#if NCPUS == 1
177 tss = &ktss; /* XXX */
178#else /* NCPUS > 1 */
179 tss = mp_ktss[mycpu]; /* XXX */
180#endif /* NCPUS > 1 */
181
182 /*
183 * ddb will overwrite whatever's in esp, so put esp0 elsewhere, too.
184 */
185 regs->esp = tss->esp0;
186 regs->efl = tss->eflags;
187 regs->eip = tss->eip;
188 regs->trapno = tss->ss0; /* XXX */
189 regs->err = tss->esp0; /* XXX */
190 regs->eax = tss->eax;
191 regs->ecx = tss->ecx;
192 regs->edx = tss->edx;
193 regs->ebx = tss->ebx;
194 regs->uesp = tss->esp;
195 regs->ebp = tss->ebp;
196 regs->esi = tss->esi;
197 regs->edi = tss->edi;
198 regs->es = tss->es;
199 regs->ss = tss->ss;
200 regs->cs = tss->cs;
201 regs->ds = tss->ds;
202 regs->fs = tss->fs;
203 regs->gs = tss->gs;
204}
205
206/*
207 * Compose a call to the debugger from the saved state in regs. (No
208 * reason not to do this in C.)
209 */
210boolean_t
211db_trap_from_asm(
212 struct i386_saved_state *regs)
213{
214 int code;
215 int type;
216
217 type = regs->trapno;
218 code = regs->err;
219 return (kdb_trap(type, code, regs));
220}
221
222int
223kdb_trap(
224 int type,
225 int code,
226 struct i386_saved_state *regs)
227{
228 extern char etext;
229 boolean_t trap_from_user;
230 spl_t s = splhigh();
231
232 switch (type) {
233 case T_DEBUG: /* single_step */
234 {
235 extern int dr_addr[];
236 int addr;
237 int status = dr6();
238
239 if (status & 0xf) { /* hmm hdw break */
240 addr = status & 0x8 ? dr_addr[3] :
241 status & 0x4 ? dr_addr[2] :
242 status & 0x2 ? dr_addr[1] :
243 dr_addr[0];
244 regs->efl |= EFL_RF;
245 db_single_step_cmd(addr, 0, 1, "p");
246 }
247 }
248 case T_INT3: /* breakpoint */
249 case T_WATCHPOINT: /* watchpoint */
250 case -1: /* keyboard interrupt */
251 break;
252
253 default:
254 if (db_recover) {
255 i386_nested_saved_state = *regs;
256 db_printf("Caught ");
257 if (type < 0 || type > TRAP_TYPES)
258 db_printf("type %d", type);
259 else
260 db_printf("%s", trap_type[type]);
261 db_printf(" trap, code = %x, pc = %x\n",
262 code, regs->eip);
263 splx(s);
264 db_error("");
265 /*NOTREACHED*/
266 }
267 kdbprinttrap(type, code, (int *)&regs->eip, regs->uesp);
268 }
269
270#if NCPUS > 1
271 disable_preemption();
272#endif /* NCPUS > 1 */
273
274 saved_ipl[cpu_number()] = s;
275 saved_state[cpu_number()] = regs;
276
277 i386_last_saved_statep = regs;
278 i386_last_kdb_sp = (unsigned) &type;
279
280#if NCPUS > 1
281 if (!kdb_enter(regs->eip))
282 goto kdb_exit;
283#endif /* NCPUS > 1 */
284
285 /* Should switch to kdb's own stack here. */
286
287 if (!IS_USER_TRAP(regs, &etext)) {
288 bzero((char *)&ddb_regs, sizeof (ddb_regs));
289 *(struct i386_saved_state_from_kernel *)&ddb_regs =
290 *(struct i386_saved_state_from_kernel *)regs;
291 trap_from_user = FALSE;
292 }
293 else {
294 ddb_regs = *regs;
295 trap_from_user = TRUE;
296 }
297 if (!trap_from_user) {
298 /*
299 * Kernel mode - esp and ss not saved
300 */
301 ddb_regs.uesp = (int)&regs->uesp; /* kernel stack pointer */
302 ddb_regs.ss = KERNEL_DS;
303 }
304
305 db_active++;
306 db_task_trap(type, code, trap_from_user);
307 db_active--;
308
309 regs->eip = ddb_regs.eip;
310 regs->efl = ddb_regs.efl;
311 regs->eax = ddb_regs.eax;
312 regs->ecx = ddb_regs.ecx;
313 regs->edx = ddb_regs.edx;
314 regs->ebx = ddb_regs.ebx;
315 if (trap_from_user) {
316 /*
317 * user mode - saved esp and ss valid
318 */
319 regs->uesp = ddb_regs.uesp; /* user stack pointer */
320 regs->ss = ddb_regs.ss & 0xffff; /* user stack segment */
321 }
322 regs->ebp = ddb_regs.ebp;
323 regs->esi = ddb_regs.esi;
324 regs->edi = ddb_regs.edi;
325 regs->es = ddb_regs.es & 0xffff;
326 regs->cs = ddb_regs.cs & 0xffff;
327 regs->ds = ddb_regs.ds & 0xffff;
328 regs->fs = ddb_regs.fs & 0xffff;
329 regs->gs = ddb_regs.gs & 0xffff;
330
331 if ((type == T_INT3) &&
332 (db_get_task_value(regs->eip,
333 BKPT_SIZE,
334 FALSE,
335 db_target_space(current_act(),
336 trap_from_user))
337 == BKPT_INST))
338 regs->eip += BKPT_SIZE;
339
340#if NCPUS > 1
341kdb_exit:
342 kdb_leave();
343#endif /* NCPUS > 1 */
344
345 saved_state[cpu_number()] = 0;
346
347#if MACH_MP_DEBUG
348 masked_state_cnt[cpu_number()] = 0;
349#endif /* MACH_MP_DEBUG */
350
351#if NCPUS > 1
352 enable_preemption();
353#endif /* NCPUS > 1 */
354
355 splx(s);
356
357 /* Allow continue to upper layers of exception handling if
358 * trap was not a debugging trap.
359 */
360
361 if (trap_from_user && type != T_DEBUG && type != T_INT3
362 && type != T_WATCHPOINT)
363 return 0;
364 else
365 return (1);
366}
367
368/*
369 * Enter KDB through a keyboard trap.
370 * We show the registers as of the keyboard interrupt
371 * instead of those at its call to KDB.
372 */
373
374spl_t kdb_oldspl;
375
376void
377kdb_kentry(
378 struct int_regs *int_regs)
379{
380 extern char etext;
381 boolean_t trap_from_user;
382 struct i386_interrupt_state *is = int_regs->is;
383 struct i386_saved_state regs;
384 spl_t s;
385
386 s = splhigh();
387 kdb_oldspl = s;
388
389 if (IS_USER_TRAP(is, &etext))
390 {
391 regs.uesp = ((int *)(is+1))[0];
392 regs.ss = ((int *)(is+1))[1];
393 }
394 else {
395 regs.ss = KERNEL_DS;
396 regs.uesp= (int)(is+1);
397 }
398 regs.efl = is->efl;
399 regs.cs = is->cs;
400 regs.eip = is->eip;
401 regs.eax = is->eax;
402 regs.ecx = is->ecx;
403 regs.edx = is->edx;
404 regs.ebx = int_regs->ebx;
405 regs.ebp = int_regs->ebp;
406 regs.esi = int_regs->esi;
407 regs.edi = int_regs->edi;
408 regs.ds = is->ds;
409 regs.es = is->es;
410 regs.fs = int_regs->fs;
411 regs.gs = int_regs->gs;
412
413#if NCPUS > 1
414 disable_preemption();
415#endif /* NCPUS > 1 */
416
417 saved_state[cpu_number()] = &regs;
418
419#if NCPUS > 1
420 if (!kdb_enter(regs.eip))
421 goto kdb_exit;
422#endif /* NCPUS > 1 */
423
424 bcopy((char *)&regs, (char *)&ddb_regs, sizeof (ddb_regs));
425 trap_from_user = IS_USER_TRAP(&ddb_regs, &etext);
426
427 db_active++;
428 db_task_trap(-1, 0, trap_from_user);
429 db_active--;
430
431 if (trap_from_user) {
432 ((int *)(is+1))[0] = ddb_regs.uesp;
433 ((int *)(is+1))[1] = ddb_regs.ss & 0xffff;
434 }
435 is->efl = ddb_regs.efl;
436 is->cs = ddb_regs.cs & 0xffff;
437 is->eip = ddb_regs.eip;
438 is->eax = ddb_regs.eax;
439 is->ecx = ddb_regs.ecx;
440 is->edx = ddb_regs.edx;
441 int_regs->ebx = ddb_regs.ebx;
442 int_regs->ebp = ddb_regs.ebp;
443 int_regs->esi = ddb_regs.esi;
444 int_regs->edi = ddb_regs.edi;
445 is->ds = ddb_regs.ds & 0xffff;
446 is->es = ddb_regs.es & 0xffff;
447 int_regs->fs = ddb_regs.fs & 0xffff;
448 int_regs->gs = ddb_regs.gs & 0xffff;
449
450#if NCPUS > 1
451kdb_exit:
452 kdb_leave();
453#endif /* NCPUS > 1 */
454 saved_state[cpu_number()] = 0;
455
456#if NCPUS > 1
457 enable_preemption();
458#endif /* NCPUS > 1 */
459
460 splx(s);
461}
462
463/*
464 * Print trap reason.
465 */
466
467void
468kdbprinttrap(
469 int type,
470 int code,
471 int *pc,
472 int sp)
473{
474 printf("kernel: ");
475 if (type < 0 || type > TRAP_TYPES)
476 db_printf("type %d", type);
477 else
478 db_printf("%s", trap_type[type]);
479 db_printf(" trap, code=%x eip@%x = %x esp=%x\n",
480 code, pc, *(int *)pc, sp);
481 db_run_mode = STEP_CONTINUE;
482}
483
484int
485db_user_to_kernel_address(
486 task_t task,
487 vm_offset_t addr,
488 unsigned *kaddr,
489 int flag)
490{
491 register pt_entry_t *ptp;
492
493 ptp = pmap_pte(task->map->pmap, addr);
494 if (ptp == PT_ENTRY_NULL || (*ptp & INTEL_PTE_VALID) == 0) {
495 if (flag) {
496 db_printf("\nno memory is assigned to address %08x\n", addr);
497 db_error(0);
498 /* NOTREACHED */
499 }
500 return(-1);
501 }
502 *kaddr = (unsigned)ptetokv(*ptp) + (addr & (INTEL_PGBYTES-1));
503 return(0);
504}
505
506/*
507 * Read bytes from kernel address space for debugger.
508 */
509
510void
511db_read_bytes(
512 vm_offset_t addr,
513 int size,
514 char *data,
515 task_t task)
516{
517 register char *src;
518 register int n;
519 unsigned kern_addr;
520
521 src = (char *)addr;
522 if (task == kernel_task || task == TASK_NULL) {
523 while (--size >= 0) {
524 if (addr++ > VM_MAX_KERNEL_ADDRESS) {
525 db_printf("\nbad address %x\n", addr);
526 db_error(0);
527 /* NOTREACHED */
528 }
529 *data++ = *src++;
530 }
531 return;
532 }
533 while (size > 0) {
534 if (db_user_to_kernel_address(task, addr, &kern_addr, 1) < 0)
535 return;
536 src = (char *)kern_addr;
537 n = intel_trunc_page(addr+INTEL_PGBYTES) - addr;
538 if (n > size)
539 n = size;
540 size -= n;
541 addr += n;
542 while (--n >= 0)
543 *data++ = *src++;
544 }
545}
546
547/*
548 * Write bytes to kernel address space for debugger.
549 */
550
551void
552db_write_bytes(
553 vm_offset_t addr,
554 int size,
555 char *data,
556 task_t task)
557{
558 register char *dst;
559
560 register pt_entry_t *ptep0 = 0;
561 pt_entry_t oldmap0 = 0;
562 vm_offset_t addr1;
563 register pt_entry_t *ptep1 = 0;
564 pt_entry_t oldmap1 = 0;
565 extern char etext;
566
567 if (task && task != kernel_task) {
568 db_write_bytes_user_space(addr, size, data, task);
569 return;
570 }
571
572
573 if (addr >= VM_MIN_KERNEL_LOADED_ADDRESS) {
574 db_write_bytes_user_space(addr, size, data, kernel_task);
575 return;
576 }
577
578 if (addr >= VM_MIN_KERNEL_ADDRESS &&
579 addr <= (vm_offset_t)&etext)
580 {
581 ptep0 = pmap_pte(kernel_pmap, addr);
582 oldmap0 = *ptep0;
583 *ptep0 |= INTEL_PTE_WRITE;
584
585 addr1 = i386_trunc_page(addr + size - 1);
586 if (i386_trunc_page(addr) != addr1) {
587 /* data crosses a page boundary */
588
589 ptep1 = pmap_pte(kernel_pmap, addr1);
590 oldmap1 = *ptep1;
591 *ptep1 |= INTEL_PTE_WRITE;
592 }
593 flush_tlb();
594 }
595
596 dst = (char *)addr;
597
598 while (--size >= 0) {
599 if (addr++ > VM_MAX_KERNEL_ADDRESS) {
600 db_printf("\nbad address %x\n", addr);
601 db_error(0);
602 /* NOTREACHED */
603 }
604 *dst++ = *data++;
605 }
606
607 if (ptep0) {
608 *ptep0 = oldmap0;
609 if (ptep1) {
610 *ptep1 = oldmap1;
611 }
612 flush_tlb();
613 }
614}
615
616void
617db_write_bytes_user_space(
618 vm_offset_t addr,
619 int size,
620 char *data,
621 task_t task)
622{
623 register char *dst;
624 register int n;
625 unsigned kern_addr;
626
627 while (size > 0) {
628 if (db_user_to_kernel_address(task, addr, &kern_addr, 1) < 0)
629 return;
630 dst = (char *)kern_addr;
631 n = intel_trunc_page(addr+INTEL_PGBYTES) - addr;
632 if (n > size)
633 n = size;
634 size -= n;
635 addr += n;
636 while (--n >= 0)
637 *dst++ = *data++;
638 }
639}
640
641boolean_t
642db_check_access(
643 vm_offset_t addr,
644 int size,
645 task_t task)
646{
647 register n;
648 unsigned kern_addr;
649
650 if (task == kernel_task || task == TASK_NULL) {
651 if (kernel_task == TASK_NULL)
652 return(TRUE);
653 task = kernel_task;
654 } else if (task == TASK_NULL) {
655 if (current_act() == THR_ACT_NULL)
656 return(FALSE);
657 task = current_act()->task;
658 }
659 while (size > 0) {
660 if (db_user_to_kernel_address(task, addr, &kern_addr, 0) < 0)
661 return(FALSE);
662 n = intel_trunc_page(addr+INTEL_PGBYTES) - addr;
663 if (n > size)
664 n = size;
665 size -= n;
666 addr += n;
667 }
668 return(TRUE);
669}
670
671boolean_t
672db_phys_eq(
673 task_t task1,
674 vm_offset_t addr1,
675 task_t task2,
676 vm_offset_t addr2)
677{
678 unsigned kern_addr1, kern_addr2;
679
680 if ((addr1 & (INTEL_PGBYTES-1)) != (addr2 & (INTEL_PGBYTES-1)))
681 return(FALSE);
682 if (task1 == TASK_NULL) {
683 if (current_act() == THR_ACT_NULL)
684 return(FALSE);
685 task1 = current_act()->task;
686 }
687 if (db_user_to_kernel_address(task1, addr1, &kern_addr1, 0) < 0 ||
688 db_user_to_kernel_address(task2, addr2, &kern_addr2, 0) < 0)
689 return(FALSE);
690 return(kern_addr1 == kern_addr2);
691}
692
693#define DB_USER_STACK_ADDR (VM_MIN_KERNEL_ADDRESS)
694#define DB_NAME_SEARCH_LIMIT (DB_USER_STACK_ADDR-(INTEL_PGBYTES*3))
695
696int
697db_search_null(
698 task_t task,
699 unsigned *svaddr,
700 unsigned evaddr,
701 unsigned *skaddr,
702 int flag)
703{
704 register unsigned vaddr;
705 register unsigned *kaddr;
706
707 kaddr = (unsigned *)*skaddr;
708 for (vaddr = *svaddr; vaddr > evaddr; vaddr -= sizeof(unsigned)) {
709 if (vaddr % INTEL_PGBYTES == 0) {
710 vaddr -= sizeof(unsigned);
711 if (db_user_to_kernel_address(task, vaddr, skaddr, 0) < 0)
712 return(-1);
713 kaddr = (unsigned *)*skaddr;
714 } else {
715 vaddr -= sizeof(unsigned);
716 kaddr--;
717 }
718 if ((*kaddr == 0) ^ (flag == 0)) {
719 *svaddr = vaddr;
720 *skaddr = (unsigned)kaddr;
721 return(0);
722 }
723 }
724 return(-1);
725}
726
727void
728db_task_name(
729 task_t task)
730{
731 register char *p;
732 register n;
733 unsigned vaddr, kaddr;
734
735 vaddr = DB_USER_STACK_ADDR;
736 kaddr = 0;
737
738 /*
739 * skip nulls at the end
740 */
741 if (db_search_null(task, &vaddr, DB_NAME_SEARCH_LIMIT, &kaddr, 0) < 0) {
742 db_printf(DB_NULL_TASK_NAME);
743 return;
744 }
745 /*
746 * search start of args
747 */
748 if (db_search_null(task, &vaddr, DB_NAME_SEARCH_LIMIT, &kaddr, 1) < 0) {
749 db_printf(DB_NULL_TASK_NAME);
750 return;
751 }
752
753 n = DB_TASK_NAME_LEN-1;
754 p = (char *)kaddr + sizeof(unsigned);
755 for (vaddr += sizeof(int); vaddr < DB_USER_STACK_ADDR && n > 0;
756 vaddr++, p++, n--) {
757 if (vaddr % INTEL_PGBYTES == 0) {
758 (void)db_user_to_kernel_address(task, vaddr, &kaddr, 0);
759 p = (char*)kaddr;
760 }
761 db_printf("%c", (*p < ' ' || *p > '~')? ' ': *p);
762 }
763 while (n-- >= 0) /* compare with >= 0 for one more space */
764 db_printf(" ");
765}
766
767#if NCPUS == 1
768
769void
770db_machdep_init(void)
771{
772 db_stacks[0] = (vm_offset_t)(db_stack_store +
773 INTSTACK_SIZE - sizeof (natural_t));
774 dbtss.esp0 = (int)(db_task_stack_store +
775 INTSTACK_SIZE - sizeof (natural_t));
776 dbtss.esp = dbtss.esp0;
777 dbtss.eip = (int)&db_task_start;
778}
779
780#else /* NCPUS > 1 */
781
782/*
783 * Code used to synchronize kdb among all cpus, one active at a time, switch
784 * from on to another using kdb_on! #cpu or cpu #cpu
785 */
786
787decl_simple_lock_data(, kdb_lock) /* kdb lock */
788
789#define db_simple_lock_init(l, e) hw_lock_init(&((l)->interlock))
790#define db_simple_lock_try(l) hw_lock_try(&((l)->interlock))
791#define db_simple_unlock(l) hw_lock_unlock(&((l)->interlock))
792
793int kdb_cpu = -1; /* current cpu running kdb */
794int kdb_debug = 0;
795int kdb_is_slave[NCPUS];
796int kdb_active[NCPUS];
797volatile unsigned int cpus_holding_bkpts; /* counter for number of cpus holding
798 breakpoints (ie: cpus that did not
799 insert back breakpoints) */
800extern boolean_t db_breakpoints_inserted;
801
802void
803db_machdep_init(void)
804{
805 int c;
806
807 db_simple_lock_init(&kdb_lock, ETAP_MISC_KDB);
808 for (c = 0; c < NCPUS; ++c) {
809 db_stacks[c] = (vm_offset_t) (db_stack_store +
810 (INTSTACK_SIZE * (c + 1)) - sizeof (natural_t));
811 if (c == master_cpu) {
812 dbtss.esp0 = (int)(db_task_stack_store +
813 (INTSTACK_SIZE * (c + 1)) - sizeof (natural_t));
814 dbtss.esp = dbtss.esp0;
815 dbtss.eip = (int)&db_task_start;
816 /*
817 * The TSS for the debugging task on each slave CPU
818 * is set up in mp_desc_init().
819 */
820 }
821 }
822}
823
824/*
825 * Called when entering kdb:
826 * Takes kdb lock. If if we were called remotely (slave state) we just
827 * wait for kdb_cpu to be equal to cpu_number(). Otherwise enter kdb if
828 * not active on another cpu.
829 * If db_pass_thru[cpu_number()] > 0, then kdb can't stop now.
830 */
831
832int
833kdb_enter(int pc)
834{
835 int my_cpu;
836 int retval;
837
838#if NCPUS > 1
839 disable_preemption();
840#endif /* NCPUS > 1 */
841
842 my_cpu = cpu_number();
843
844 if (db_pass_thru[my_cpu]) {
845 retval = 0;
846 goto kdb_exit;
847 }
848
849 kdb_active[my_cpu]++;
850 lock_kdb();
851
852 if (kdb_debug)
853 db_printf("kdb_enter: cpu %d, is_slave %d, kdb_cpu %d, run mode %d pc %x (%x) holds %d\n",
854 my_cpu, kdb_is_slave[my_cpu], kdb_cpu,
855 db_run_mode, pc, *(int *)pc, cpus_holding_bkpts);
856 if (db_breakpoints_inserted)
857 cpus_holding_bkpts++;
858 if (kdb_cpu == -1 && !kdb_is_slave[my_cpu]) {
859 kdb_cpu = my_cpu;
860 remote_kdb(); /* stop other cpus */
861 retval = 1;
862 } else if (kdb_cpu == my_cpu)
863 retval = 1;
864 else
865 retval = 0;
866
867kdb_exit:
868#if NCPUS > 1
869 enable_preemption();
870#endif /* NCPUS > 1 */
871
872 return (retval);
873}
874
875void
876kdb_leave(void)
877{
878 int my_cpu;
879 boolean_t wait = FALSE;
880
881#if NCPUS > 1
882 disable_preemption();
883#endif /* NCPUS > 1 */
884
885 my_cpu = cpu_number();
886
887 if (db_run_mode == STEP_CONTINUE) {
888 wait = TRUE;
889 kdb_cpu = -1;
890 }
891 if (db_breakpoints_inserted)
892 cpus_holding_bkpts--;
893 if (kdb_is_slave[my_cpu])
894 kdb_is_slave[my_cpu]--;
895 if (kdb_debug)
896 db_printf("kdb_leave: cpu %d, kdb_cpu %d, run_mode %d pc %x (%x) holds %d\n",
897 my_cpu, kdb_cpu, db_run_mode,
898 ddb_regs.eip, *(int *)ddb_regs.eip,
899 cpus_holding_bkpts);
900 clear_kdb_intr();
901 unlock_kdb();
902 kdb_active[my_cpu]--;
903
904#if NCPUS > 1
905 enable_preemption();
906#endif /* NCPUS > 1 */
907
908 if (wait) {
909 while(cpus_holding_bkpts);
910 }
911}
912
913void
914lock_kdb(void)
915{
916 int my_cpu;
917 register i;
918 extern void kdb_console(void);
919
920#if NCPUS > 1
921 disable_preemption();
922#endif /* NCPUS > 1 */
923
924 my_cpu = cpu_number();
925
926 for(;;) {
927 kdb_console();
928 if (kdb_cpu != -1 && kdb_cpu != my_cpu) {
929 continue;
930 }
931 if (db_simple_lock_try(&kdb_lock)) {
932 if (kdb_cpu == -1 || kdb_cpu == my_cpu)
933 break;
934 db_simple_unlock(&kdb_lock);
935 }
936 }
937
938#if NCPUS > 1
939 enable_preemption();
940#endif /* NCPUS > 1 */
941}
942
943#if TIME_STAMP
944extern unsigned old_time_stamp;
945#endif /* TIME_STAMP */
946
947void
948unlock_kdb(void)
949{
950 db_simple_unlock(&kdb_lock);
951#if TIME_STAMP
952 old_time_stamp = 0;
953#endif /* TIME_STAMP */
954}
955
956
957#ifdef __STDC__
958#define KDB_SAVE(type, name) extern type name; type name##_save = name
959#define KDB_RESTORE(name) name = name##_save
960#else /* __STDC__ */
961#define KDB_SAVE(type, name) extern type name; type name/**/_save = name
962#define KDB_RESTORE(name) name = name/**/_save
963#endif /* __STDC__ */
964
965#define KDB_SAVE_CTXT() \
966 KDB_SAVE(int, db_run_mode); \
967 KDB_SAVE(boolean_t, db_sstep_print); \
968 KDB_SAVE(int, db_loop_count); \
969 KDB_SAVE(int, db_call_depth); \
970 KDB_SAVE(int, db_inst_count); \
971 KDB_SAVE(int, db_last_inst_count); \
972 KDB_SAVE(int, db_load_count); \
973 KDB_SAVE(int, db_store_count); \
974 KDB_SAVE(boolean_t, db_cmd_loop_done); \
975 KDB_SAVE(jmp_buf_t *, db_recover); \
976 KDB_SAVE(db_addr_t, db_dot); \
977 KDB_SAVE(db_addr_t, db_last_addr); \
978 KDB_SAVE(db_addr_t, db_prev); \
979 KDB_SAVE(db_addr_t, db_next); \
980 KDB_SAVE(db_regs_t, ddb_regs);
981
982#define KDB_RESTORE_CTXT() \
983 KDB_RESTORE(db_run_mode); \
984 KDB_RESTORE(db_sstep_print); \
985 KDB_RESTORE(db_loop_count); \
986 KDB_RESTORE(db_call_depth); \
987 KDB_RESTORE(db_inst_count); \
988 KDB_RESTORE(db_last_inst_count); \
989 KDB_RESTORE(db_load_count); \
990 KDB_RESTORE(db_store_count); \
991 KDB_RESTORE(db_cmd_loop_done); \
992 KDB_RESTORE(db_recover); \
993 KDB_RESTORE(db_dot); \
994 KDB_RESTORE(db_last_addr); \
995 KDB_RESTORE(db_prev); \
996 KDB_RESTORE(db_next); \
997 KDB_RESTORE(ddb_regs);
998
999/*
1000 * switch to another cpu
1001 */
1002
1003void
1004kdb_on(
1005 int cpu)
1006{
1007 KDB_SAVE_CTXT();
1008 if (cpu < 0 || cpu >= NCPUS || !kdb_active[cpu])
1009 return;
1010 db_set_breakpoints();
1011 db_set_watchpoints();
1012 kdb_cpu = cpu;
1013 unlock_kdb();
1014 lock_kdb();
1015 db_clear_breakpoints();
1016 db_clear_watchpoints();
1017 KDB_RESTORE_CTXT();
1018 if (kdb_cpu == -1) {/* someone continued */
1019 kdb_cpu = cpu_number();
1020 db_continue_cmd(0, 0, 0, "");
1021 }
1022}
1023
1024#endif /* NCPUS > 1 */
1025
1026void db_reboot(
1027 db_expr_t addr,
1028 boolean_t have_addr,
1029 db_expr_t count,
1030 char *modif)
1031{
1032 boolean_t reboot = TRUE;
1033 char *cp, c;
1034
1035 cp = modif;
1036 while ((c = *cp++) != 0) {
1037 if (c == 'r') /* reboot */
1038 reboot = TRUE;
1039 if (c == 'h') /* halt */
1040 reboot = FALSE;
1041 }
1042 halt_all_cpus(reboot);
1043}