]> git.saurik.com Git - apple/xnu.git/blame - osfmk/kdp/ml/i386/kdp_machdep.c
xnu-1456.1.26.tar.gz
[apple/xnu.git] / osfmk / kdp / ml / i386 / kdp_machdep.c
CommitLineData
1c79356b 1/*
2d21ac55 2 * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
1c79356b 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
2d21ac55
A
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 License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
8f6c56a5 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b 27 */
1c79356b 28
0c530ab8 29#include <mach_kdp.h>
1c79356b
A
30#include <mach/mach_types.h>
31#include <mach/machine.h>
32#include <mach/exception_types.h>
91447636 33#include <kern/cpu_data.h>
1c79356b 34#include <i386/trap.h>
55e303ae 35#include <i386/mp.h>
1c79356b 36#include <kdp/kdp_internal.h>
2d21ac55 37#include <kdp/kdp_callout.h>
0c530ab8
A
38#include <mach-o/loader.h>
39#include <mach-o/nlist.h>
40#include <IOKit/IOPlatformExpert.h> /* for PE_halt_restart */
41#include <kern/machine.h> /* for halt_all_cpus */
b0d623f7 42#include <libkern/OSAtomic.h>
0c530ab8
A
43
44#include <kern/thread.h>
45#include <i386/thread.h>
46#include <vm/vm_map.h>
47#include <i386/pmap.h>
2d21ac55 48#include <kern/kalloc.h>
1c79356b
A
49
50#define KDP_TEST_HARNESS 0
51#if KDP_TEST_HARNESS
52#define dprintf(x) printf x
53#else
54#define dprintf(x)
55#endif
56
0c530ab8
A
57extern cpu_type_t cpuid_cputype(void);
58extern cpu_subtype_t cpuid_cpusubtype(void);
91447636
A
59
60void print_saved_state(void *);
61void kdp_call(void);
62int kdp_getc(void);
63boolean_t kdp_call_kdb(void);
64void kdp_getstate(i386_thread_state_t *);
65void kdp_setstate(i386_thread_state_t *);
66void kdp_print_phys(int);
0c530ab8
A
67
68int
2d21ac55 69machine_trace_thread(thread_t thread, char *tracepos, char *tracebound, int nframes, boolean_t user_p);
0c530ab8
A
70
71int
2d21ac55
A
72machine_trace_thread64(thread_t thread, char *tracepos, char *tracebound, int nframes, boolean_t user_p);
73
74unsigned
75machine_read64(addr64_t srcaddr, caddr_t dstaddr, uint32_t len);
0c530ab8 76
2d21ac55
A
77static void kdp_callouts(kdp_event_t event);
78
1c79356b
A
79void
80kdp_exception(
81 unsigned char *pkt,
82 int *len,
83 unsigned short *remote_port,
84 unsigned int exception,
85 unsigned int code,
86 unsigned int subcode
87)
88{
89 kdp_exception_t *rq = (kdp_exception_t *)pkt;
90
91 rq->hdr.request = KDP_EXCEPTION;
92 rq->hdr.is_reply = 0;
93 rq->hdr.seq = kdp.exception_seq;
94 rq->hdr.key = 0;
95 rq->hdr.len = sizeof (*rq);
96
97 rq->n_exc_info = 1;
98 rq->exc_info[0].cpu = 0;
99 rq->exc_info[0].exception = exception;
100 rq->exc_info[0].code = code;
101 rq->exc_info[0].subcode = subcode;
102
103 rq->hdr.len += rq->n_exc_info * sizeof (kdp_exc_info_t);
104
105 bcopy((char *)rq, (char *)pkt, rq->hdr.len);
106
107 kdp.exception_ack_needed = TRUE;
108
109 *remote_port = kdp.exception_port;
110 *len = rq->hdr.len;
111}
112
113boolean_t
114kdp_exception_ack(
115 unsigned char *pkt,
116 int len
117)
118{
119 kdp_exception_ack_t *rq = (kdp_exception_ack_t *)pkt;
120
91447636 121 if (((unsigned int) len) < sizeof (*rq))
1c79356b
A
122 return(FALSE);
123
124 if (!rq->hdr.is_reply || rq->hdr.request != KDP_EXCEPTION)
125 return(FALSE);
126
127 dprintf(("kdp_exception_ack seq %x %x\n", rq->hdr.seq, kdp.exception_seq));
128
129 if (rq->hdr.seq == kdp.exception_seq) {
130 kdp.exception_ack_needed = FALSE;
131 kdp.exception_seq++;
132 }
133 return(TRUE);
134}
135
136void
137kdp_getstate(
0c530ab8 138 x86_thread_state32_t *state
1c79356b
A
139)
140{
0c530ab8
A
141 static x86_thread_state32_t null_state;
142 x86_saved_state32_t *saved_state;
1c79356b 143
0c530ab8 144 saved_state = (x86_saved_state32_t *)kdp.saved_state;
1c79356b 145
91447636 146 *state = null_state;
1c79356b
A
147 state->eax = saved_state->eax;
148 state->ebx = saved_state->ebx;
149 state->ecx = saved_state->ecx;
150 state->edx = saved_state->edx;
151 state->edi = saved_state->edi;
152 state->esi = saved_state->esi;
153 state->ebp = saved_state->ebp;
154
cf7d32b8
A
155 if ((saved_state->cs & SEL_PL) == SEL_PL_K) { /* Kernel state? */
156 if (cpu_mode_is64bit())
157 state->esp = (uint32_t) saved_state->uesp;
158 else
159 state->esp = ((uint32_t)saved_state) + offsetof(x86_saved_state_t, ss_32) + sizeof(x86_saved_state32_t);
1c79356b
A
160 state->ss = KERNEL_DS;
161 } else {
162 state->esp = saved_state->uesp;
163 state->ss = saved_state->ss;
164 }
165
166 state->eflags = saved_state->efl;
167 state->eip = saved_state->eip;
168 state->cs = saved_state->cs;
169 state->ds = saved_state->ds;
170 state->es = saved_state->es;
171 state->fs = saved_state->fs;
172 state->gs = saved_state->gs;
173}
174
175
176void
177kdp_setstate(
0c530ab8 178 x86_thread_state32_t *state
1c79356b
A
179)
180{
0c530ab8 181 x86_saved_state32_t *saved_state;
1c79356b 182
0c530ab8 183 saved_state = (x86_saved_state32_t *)kdp.saved_state;
1c79356b
A
184
185 saved_state->eax = state->eax;
186 saved_state->ebx = state->ebx;
187 saved_state->ecx = state->ecx;
188 saved_state->edx = state->edx;
189 saved_state->edi = state->edi;
190 saved_state->esi = state->esi;
191 saved_state->ebp = state->ebp;
192 saved_state->efl = state->eflags;
193#if 0
194 saved_state->frame.eflags &= ~( EFL_VM | EFL_NT | EFL_IOPL | EFL_CLR );
195 saved_state->frame.eflags |= ( EFL_IF | EFL_SET );
196#endif
197 saved_state->eip = state->eip;
1c79356b
A
198}
199
200
201kdp_error_t
202kdp_machine_read_regs(
91447636
A
203 __unused unsigned int cpu,
204 __unused unsigned int flavor,
1c79356b 205 char *data,
91447636 206 __unused int *size
1c79356b
A
207)
208{
2d21ac55 209 static x86_float_state32_t null_fpstate;
91447636 210
1c79356b
A
211 switch (flavor) {
212
0c530ab8 213 case x86_THREAD_STATE32:
1c79356b 214 dprintf(("kdp_readregs THREAD_STATE\n"));
0c530ab8
A
215 kdp_getstate((x86_thread_state32_t *)data);
216 *size = sizeof (x86_thread_state32_t);
1c79356b
A
217 return KDPERR_NO_ERROR;
218
0c530ab8 219 case x86_FLOAT_STATE32:
1c79356b 220 dprintf(("kdp_readregs THREAD_FPSTATE\n"));
0c530ab8
A
221 *(x86_float_state32_t *)data = null_fpstate;
222 *size = sizeof (x86_float_state32_t);
1c79356b
A
223 return KDPERR_NO_ERROR;
224
225 default:
91447636
A
226 dprintf(("kdp_readregs bad flavor %d\n", flavor));
227 *size = 0;
1c79356b
A
228 return KDPERR_BADFLAVOR;
229 }
230}
231
232kdp_error_t
233kdp_machine_write_regs(
91447636 234 __unused unsigned int cpu,
1c79356b
A
235 unsigned int flavor,
236 char *data,
91447636 237 __unused int *size
1c79356b
A
238)
239{
240 switch (flavor) {
241
0c530ab8 242 case x86_THREAD_STATE32:
1c79356b 243 dprintf(("kdp_writeregs THREAD_STATE\n"));
0c530ab8 244 kdp_setstate((x86_thread_state32_t *)data);
1c79356b
A
245 return KDPERR_NO_ERROR;
246
0c530ab8 247 case x86_FLOAT_STATE32:
1c79356b
A
248 dprintf(("kdp_writeregs THREAD_FPSTATE\n"));
249 return KDPERR_NO_ERROR;
250
251 default:
252 dprintf(("kdp_writeregs bad flavor %d\n"));
253 return KDPERR_BADFLAVOR;
254 }
255}
256
257
258
259void
260kdp_machine_hostinfo(
261 kdp_hostinfo_t *hostinfo
262)
263{
1c79356b
A
264 int i;
265
266 hostinfo->cpus_mask = 0;
267
268 for (i = 0; i < machine_info.max_cpus; i++) {
91447636 269 if (cpu_data_ptr[i] == NULL)
1c79356b
A
270 continue;
271
272 hostinfo->cpus_mask |= (1 << i);
273 }
274
0c530ab8
A
275 hostinfo->cpu_type = cpuid_cputype();
276 hostinfo->cpu_subtype = cpuid_cpusubtype();
1c79356b
A
277}
278
279void
280kdp_panic(
281 const char *msg
282)
283{
91447636 284 kprintf("kdp panic: %s\n", msg);
1c79356b
A
285 __asm__ volatile("hlt");
286}
287
288
289void
b0d623f7 290kdp_machine_reboot(void)
1c79356b 291{
0c530ab8
A
292 printf("Attempting system restart...");
293 /* Call the platform specific restart*/
294 if (PE_halt_restart)
295 (*PE_halt_restart)(kPERestartCPU);
296 /* If we do reach this, give up */
297 halt_all_cpus(TRUE);
1c79356b
A
298}
299
300int
301kdp_intr_disbl(void)
302{
303 return splhigh();
304}
305
306void
307kdp_intr_enbl(int s)
308{
309 splx(s);
310}
311
312int
2d21ac55 313kdp_getc(void)
1c79356b
A
314{
315 return cnmaygetc();
316}
317
318void
319kdp_us_spin(int usec)
320{
1c79356b
A
321 delay(usec/100);
322}
323
324void print_saved_state(void *state)
325{
0c530ab8 326 x86_saved_state32_t *saved_state;
1c79356b
A
327
328 saved_state = state;
329
91447636 330 kprintf("pc = 0x%x\n", saved_state->eip);
0c530ab8 331 kprintf("cr2= 0x%x\n", saved_state->cr2);
91447636 332 kprintf("rp = TODO FIXME\n");
2d21ac55 333 kprintf("sp = %p\n", saved_state);
1c79356b
A
334
335}
336
337void
2d21ac55 338kdp_sync_cache(void)
1c79356b
A
339{
340 return; /* No op here. */
341}
342
343void
2d21ac55 344kdp_call(void)
1c79356b
A
345{
346 __asm__ volatile ("int $3"); /* Let the processor do the work */
347}
348
349
350typedef struct _cframe_t {
351 struct _cframe_t *prev;
352 unsigned caller;
353 unsigned args[0];
354} cframe_t;
355
91447636
A
356#include <i386/pmap.h>
357extern pt_entry_t *DMAP2;
358extern caddr_t DADDR2;
359
360void
361kdp_print_phys(int src)
362{
363 unsigned int *iptr;
364 int i;
365
366 *(int *) DMAP2 = 0x63 | (src & 0xfffff000);
367 invlpg((u_int) DADDR2);
368 iptr = (unsigned int *) DADDR2;
369 for (i = 0; i < 100; i++) {
370 kprintf("0x%x ", *iptr++);
371 if ((i % 8) == 0)
372 kprintf("\n");
373 }
374 kprintf("\n");
375 *(int *) DMAP2 = 0;
376
377}
378
0c530ab8 379boolean_t
1c79356b 380kdp_i386_trap(
2d21ac55 381 unsigned int trapno,
0c530ab8 382 x86_saved_state32_t *saved_state,
1c79356b
A
383 kern_return_t result,
384 vm_offset_t va
385)
386{
387 unsigned int exception, subcode = 0, code;
388
0c530ab8 389 if (trapno != T_INT3 && trapno != T_DEBUG) {
2d21ac55
A
390 kprintf("Debugger: Unexpected kernel trap number: "
391 "0x%x, EIP: 0x%x, CR2: 0x%x\n",
0c530ab8
A
392 trapno, saved_state->eip, saved_state->cr2);
393 if (!kdp.is_conn)
394 return FALSE;
395 }
396
397 mp_kdp_enter();
2d21ac55
A
398 kdp_callouts(KDP_EVENT_ENTER);
399
400 if (saved_state->efl & EFL_TF) {
401 enable_preemption_no_check();
402 }
6601e61a 403
1c79356b
A
404 switch (trapno) {
405
406 case T_DIVIDE_ERROR:
407 exception = EXC_ARITHMETIC;
408 code = EXC_I386_DIVERR;
409 break;
410
411 case T_OVERFLOW:
412 exception = EXC_SOFTWARE;
413 code = EXC_I386_INTOFLT;
414 break;
415
416 case T_OUT_OF_BOUNDS:
417 exception = EXC_ARITHMETIC;
418 code = EXC_I386_BOUNDFLT;
419 break;
420
421 case T_INVALID_OPCODE:
422 exception = EXC_BAD_INSTRUCTION;
423 code = EXC_I386_INVOPFLT;
424 break;
425
426 case T_SEGMENT_NOT_PRESENT:
427 exception = EXC_BAD_INSTRUCTION;
428 code = EXC_I386_SEGNPFLT;
429 subcode = saved_state->err;
430 break;
431
432 case T_STACK_FAULT:
433 exception = EXC_BAD_INSTRUCTION;
434 code = EXC_I386_STKFLT;
435 subcode = saved_state->err;
436 break;
437
438 case T_GENERAL_PROTECTION:
439 exception = EXC_BAD_INSTRUCTION;
440 code = EXC_I386_GPFLT;
441 subcode = saved_state->err;
442 break;
443
444 case T_PAGE_FAULT:
445 exception = EXC_BAD_ACCESS;
446 code = result;
447 subcode = va;
448 break;
449
450 case T_WATCHPOINT:
451 exception = EXC_SOFTWARE;
452 code = EXC_I386_ALIGNFLT;
453 break;
454
455 case T_DEBUG:
456 case T_INT3:
457 exception = EXC_BREAKPOINT;
458 code = EXC_I386_BPTFLT;
459 break;
460
461 default:
462 exception = EXC_BAD_INSTRUCTION;
463 code = trapno;
464 break;
465 }
466
1c79356b 467 kdp_raise_exception(exception, code, subcode, saved_state);
2d21ac55
A
468 /* If the instruction single step bit is set, disable kernel preemption
469 */
470 if (saved_state->efl & EFL_TF) {
471 disable_preemption();
472 }
55e303ae 473
2d21ac55 474 kdp_callouts(KDP_EVENT_EXIT);
55e303ae 475 mp_kdp_exit();
0c530ab8
A
476
477 return TRUE;
1c79356b
A
478}
479
480boolean_t
481kdp_call_kdb(
482 void)
483{
484 return(FALSE);
485}
9bccf70c 486
b0d623f7
A
487void
488kdp_machine_get_breakinsn(
489 uint8_t *bytes,
490 uint32_t *size
491)
9bccf70c 492{
b0d623f7
A
493 bytes[0] = 0xcc;
494 *size = 1;
9bccf70c 495}
cf7d32b8 496
0c530ab8
A
497extern pmap_t kdp_pmap;
498
499#define RETURN_OFFSET 4
500int
2d21ac55 501machine_trace_thread(thread_t thread, char *tracepos, char *tracebound, int nframes, boolean_t user_p)
0c530ab8
A
502{
503 uint32_t *tracebuf = (uint32_t *)tracepos;
504 uint32_t fence = 0;
505 uint32_t stackptr = 0;
506 uint32_t stacklimit = 0xfc000000;
507 int framecount = 0;
508 uint32_t init_eip = 0;
509 uint32_t prevsp = 0;
510 uint32_t framesize = 2 * sizeof(vm_offset_t);
511
512 if (user_p) {
513 x86_saved_state32_t *iss32;
514
515 iss32 = USER_REGS32(thread);
516
2d21ac55
A
517 init_eip = iss32->eip;
518 stackptr = iss32->ebp;
0c530ab8
A
519
520 /* This bound isn't useful, but it doesn't hinder us*/
521 stacklimit = 0xffffffff;
522 kdp_pmap = thread->task->map->pmap;
523 }
524 else {
525 /*Examine the i386_saved_state at the base of the kernel stack*/
526 stackptr = STACK_IKS(thread->kernel_stack)->k_ebp;
527 init_eip = STACK_IKS(thread->kernel_stack)->k_eip;
528 }
529
530 *tracebuf++ = init_eip;
531
532 for (framecount = 0; framecount < nframes; framecount++) {
533
2d21ac55 534 if ((uint32_t)(tracebound - ((char *)tracebuf)) < (4 * framesize)) {
0c530ab8
A
535 tracebuf--;
536 break;
537 }
538
539 *tracebuf++ = stackptr;
540/* Invalid frame, or hit fence */
541 if (!stackptr || (stackptr == fence)) {
542 break;
543 }
b0d623f7 544
0c530ab8
A
545 /* Unaligned frame */
546 if (stackptr & 0x0000003) {
547 break;
548 }
b0d623f7 549
0c530ab8
A
550 if (stackptr > stacklimit) {
551 break;
552 }
b0d623f7
A
553
554 if (stackptr <= prevsp) {
555 break;
556 }
0c530ab8 557
b0d623f7 558 if (kdp_machine_vm_read((mach_vm_address_t)(stackptr + RETURN_OFFSET), (caddr_t) tracebuf, sizeof(caddr_t)) != sizeof(caddr_t)) {
0c530ab8
A
559 break;
560 }
561 tracebuf++;
562
563 prevsp = stackptr;
b0d623f7 564 if (kdp_machine_vm_read((mach_vm_address_t)stackptr, (caddr_t) &stackptr, sizeof(caddr_t)) != sizeof(caddr_t)) {
0c530ab8
A
565 *tracebuf++ = 0;
566 break;
567 }
568 }
569
570 kdp_pmap = 0;
571
2d21ac55
A
572 return (uint32_t) (((char *) tracebuf) - tracepos);
573}
574
575#define RETURN_OFFSET64 8
576/* Routine to encapsulate the 64-bit address read hack*/
577unsigned
578machine_read64(addr64_t srcaddr, caddr_t dstaddr, uint32_t len)
579{
b0d623f7 580 return (unsigned)kdp_machine_vm_read(srcaddr, dstaddr, len);
0c530ab8
A
581}
582
0c530ab8 583int
2d21ac55
A
584machine_trace_thread64(thread_t thread, char *tracepos, char *tracebound, int nframes, boolean_t user_p)
585{
586 uint64_t *tracebuf = (uint64_t *)tracepos;
587 uint32_t fence = 0;
588 addr64_t stackptr = 0;
589 uint64_t stacklimit = 0xfc000000;
590 int framecount = 0;
591 addr64_t init_rip = 0;
592 addr64_t prevsp = 0;
593 unsigned framesize = 2 * sizeof(addr64_t);
594
595 if (user_p) {
596 x86_saved_state64_t *iss64;
597 iss64 = USER_REGS64(thread);
598 init_rip = iss64->isf.rip;
599 stackptr = iss64->rbp;
600 stacklimit = 0xffffffffffffffffULL;
601 kdp_pmap = thread->task->map->pmap;
602 }
2d21ac55
A
603
604 *tracebuf++ = init_rip;
605
606 for (framecount = 0; framecount < nframes; framecount++) {
607
608 if ((uint32_t)(tracebound - ((char *)tracebuf)) < (4 * framesize)) {
609 tracebuf--;
610 break;
611 }
612
613 *tracebuf++ = stackptr;
614
615 if (!stackptr || (stackptr == fence)){
616 break;
617 }
b0d623f7 618
2d21ac55
A
619 if (stackptr & 0x0000003) {
620 break;
621 }
622 if (stackptr > stacklimit) {
623 break;
624 }
625
b0d623f7
A
626 if (stackptr <= prevsp) {
627 break;
628 }
629
2d21ac55
A
630 if (machine_read64(stackptr + RETURN_OFFSET64, (caddr_t) tracebuf, sizeof(addr64_t)) != sizeof(addr64_t)) {
631 break;
632 }
633 tracebuf++;
634
635 prevsp = stackptr;
636 if (machine_read64(stackptr, (caddr_t) &stackptr, sizeof(addr64_t)) != sizeof(addr64_t)) {
637 *tracebuf++ = 0;
638 break;
639 }
640 }
641
642 kdp_pmap = NULL;
643
644 return (uint32_t) (((char *) tracebuf) - tracepos);
645}
646
647static struct kdp_callout {
648 struct kdp_callout *callout_next;
649 kdp_callout_fn_t callout_fn;
650 void *callout_arg;
651} *kdp_callout_list = NULL;
652
653
654/*
655 * Called from kernel context to register a kdp event callout.
656 */
657void
658kdp_register_callout(
659 kdp_callout_fn_t fn,
660 void *arg)
661{
662 struct kdp_callout *kcp;
663 struct kdp_callout *list_head;
664
665 kcp = kalloc(sizeof(*kcp));
666 if (kcp == NULL)
667 panic("kdp_register_callout() kalloc failed");
668
669 kcp->callout_fn = fn;
670 kcp->callout_arg = arg;
671
672 /* Lock-less list insertion using compare and exchange. */
673 do {
674 list_head = kdp_callout_list;
675 kcp->callout_next = list_head;
b0d623f7 676 } while (!OSCompareAndSwapPtr(list_head, kcp, (void * volatile *)&kdp_callout_list));
2d21ac55
A
677}
678
679/*
680 * Called at exception/panic time when extering or exiting kdp.
681 * We are single-threaded at this time and so we don't use locks.
682 */
683static void
684kdp_callouts(kdp_event_t event)
685{
686 struct kdp_callout *kcp = kdp_callout_list;
687
688 while (kcp) {
689 kcp->callout_fn(kcp->callout_arg, event);
690 kcp = kcp->callout_next;
691 }
692}
693
694void
695kdp_ml_enter_debugger(void)
696{
697 __asm__ __volatile__("int3");
0c530ab8 698}