X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/8ad349bb6ed4a0be06e34c92be0d98b92e078db4..b0d623f7f2ae71ed96e60569f61f9a9a27016e80:/osfmk/kdp/ml/i386/kdp_machdep.c diff --git a/osfmk/kdp/ml/i386/kdp_machdep.c b/osfmk/kdp/ml/i386/kdp_machdep.c index 5faa82a74..8beb2959e 100644 --- a/osfmk/kdp/ml/i386/kdp_machdep.c +++ b/osfmk/kdp/ml/i386/kdp_machdep.c @@ -1,33 +1,32 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_OSREFERENCE_HEADER_START@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. The rights granted to you under the - * License may not be used to create, or enable the creation or - * redistribution of, unlawful or unlicensed copies of an Apple operating - * system, or to circumvent, violate, or enable the circumvention or - * violation of, any terms of an Apple operating system software license - * agreement. - * - * Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and * limitations under the License. - * - * @APPLE_LICENSE_OSREFERENCE_HEADER_END@ + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ +#include #include #include #include @@ -35,6 +34,18 @@ #include #include #include +#include +#include +#include +#include /* for PE_halt_restart */ +#include /* for halt_all_cpus */ +#include + +#include +#include +#include +#include +#include #define KDP_TEST_HARNESS 0 #if KDP_TEST_HARNESS @@ -43,7 +54,8 @@ #define dprintf(x) #endif -extern void kdreboot(void); +extern cpu_type_t cpuid_cputype(void); +extern cpu_subtype_t cpuid_cpusubtype(void); void print_saved_state(void *); void kdp_call(void); @@ -52,12 +64,17 @@ boolean_t kdp_call_kdb(void); void kdp_getstate(i386_thread_state_t *); void kdp_setstate(i386_thread_state_t *); void kdp_print_phys(int); -void kdp_i386_backtrace(void *, int); -void kdp_i386_trap( - unsigned int, - struct i386_saved_state *, - kern_return_t, - vm_offset_t); + +int +machine_trace_thread(thread_t thread, char *tracepos, char *tracebound, int nframes, boolean_t user_p); + +int +machine_trace_thread64(thread_t thread, char *tracepos, char *tracebound, int nframes, boolean_t user_p); + +unsigned +machine_read64(addr64_t srcaddr, caddr_t dstaddr, uint32_t len); + +static void kdp_callouts(kdp_event_t event); void kdp_exception( @@ -118,13 +135,13 @@ kdp_exception_ack( void kdp_getstate( - i386_thread_state_t *state + x86_thread_state32_t *state ) { - static i386_thread_state_t null_state; - struct i386_saved_state *saved_state; + static x86_thread_state32_t null_state; + x86_saved_state32_t *saved_state; - saved_state = (struct i386_saved_state *)kdp.saved_state; + saved_state = (x86_saved_state32_t *)kdp.saved_state; *state = null_state; state->eax = saved_state->eax; @@ -135,8 +152,11 @@ kdp_getstate( state->esi = saved_state->esi; state->ebp = saved_state->ebp; - if ((saved_state->cs & 0x3) == 0){ /* Kernel State */ - state->esp = (unsigned int) &saved_state->uesp; + if ((saved_state->cs & SEL_PL) == SEL_PL_K) { /* Kernel state? */ + if (cpu_mode_is64bit()) + state->esp = (uint32_t) saved_state->uesp; + else + state->esp = ((uint32_t)saved_state) + offsetof(x86_saved_state_t, ss_32) + sizeof(x86_saved_state32_t); state->ss = KERNEL_DS; } else { state->esp = saved_state->uesp; @@ -155,12 +175,12 @@ kdp_getstate( void kdp_setstate( - i386_thread_state_t *state + x86_thread_state32_t *state ) { - struct i386_saved_state *saved_state; + x86_saved_state32_t *saved_state; - saved_state = (struct i386_saved_state *)kdp.saved_state; + saved_state = (x86_saved_state32_t *)kdp.saved_state; saved_state->eax = state->eax; saved_state->ebx = state->ebx; @@ -175,8 +195,6 @@ kdp_setstate( saved_state->frame.eflags |= ( EFL_IF | EFL_SET ); #endif saved_state->eip = state->eip; - saved_state->fs = state->fs; - saved_state->gs = state->gs; } @@ -188,20 +206,20 @@ kdp_machine_read_regs( __unused int *size ) { - static i386_thread_fpstate_t null_fpstate; + static x86_float_state32_t null_fpstate; switch (flavor) { - case i386_THREAD_STATE: + case x86_THREAD_STATE32: dprintf(("kdp_readregs THREAD_STATE\n")); - kdp_getstate((i386_thread_state_t *)data); - *size = sizeof (i386_thread_state_t); + kdp_getstate((x86_thread_state32_t *)data); + *size = sizeof (x86_thread_state32_t); return KDPERR_NO_ERROR; - case i386_THREAD_FPSTATE: + case x86_FLOAT_STATE32: dprintf(("kdp_readregs THREAD_FPSTATE\n")); - *(i386_thread_fpstate_t *)data = null_fpstate; - *size = sizeof (i386_thread_fpstate_t); + *(x86_float_state32_t *)data = null_fpstate; + *size = sizeof (x86_float_state32_t); return KDPERR_NO_ERROR; default: @@ -221,12 +239,12 @@ kdp_machine_write_regs( { switch (flavor) { - case i386_THREAD_STATE: + case x86_THREAD_STATE32: dprintf(("kdp_writeregs THREAD_STATE\n")); - kdp_setstate((i386_thread_state_t *)data); + kdp_setstate((x86_thread_state32_t *)data); return KDPERR_NO_ERROR; - case i386_THREAD_FPSTATE: + case x86_FLOAT_STATE32: dprintf(("kdp_writeregs THREAD_FPSTATE\n")); return KDPERR_NO_ERROR; @@ -254,9 +272,8 @@ kdp_machine_hostinfo( hostinfo->cpus_mask |= (1 << i); } - /* FIXME?? */ - hostinfo->cpu_type = CPU_TYPE_I386; - hostinfo->cpu_subtype = CPU_SUBTYPE_486; + hostinfo->cpu_type = cpuid_cputype(); + hostinfo->cpu_subtype = cpuid_cpusubtype(); } void @@ -270,9 +287,14 @@ kdp_panic( void -kdp_reboot(void) +kdp_machine_reboot(void) { - kdreboot(); + printf("Attempting system restart..."); + /* Call the platform specific restart*/ + if (PE_halt_restart) + (*PE_halt_restart)(kPERestartCPU); + /* If we do reach this, give up */ + halt_all_cpus(TRUE); } int @@ -288,7 +310,7 @@ kdp_intr_enbl(int s) } int -kdp_getc() +kdp_getc(void) { return cnmaygetc(); } @@ -301,25 +323,25 @@ kdp_us_spin(int usec) void print_saved_state(void *state) { - struct i386_saved_state *saved_state; + x86_saved_state32_t *saved_state; saved_state = state; kprintf("pc = 0x%x\n", saved_state->eip); - kprintf("cr3= 0x%x\n", saved_state->cr2); + kprintf("cr2= 0x%x\n", saved_state->cr2); kprintf("rp = TODO FIXME\n"); - kprintf("sp = 0x%x\n", saved_state->esp); + kprintf("sp = %p\n", saved_state); } void -kdp_sync_cache() +kdp_sync_cache(void) { return; /* No op here. */ } void -kdp_call() +kdp_call(void) { __asm__ volatile ("int $3"); /* Let the processor do the work */ } @@ -354,51 +376,30 @@ kdp_print_phys(int src) } - -#define MAX_FRAME_DELTA 65536 - -void -kdp_i386_backtrace(void *_frame, int nframes) -{ - cframe_t *frame = (cframe_t *)_frame; - int i; - - for (i=0; i VM_MAX_KERNEL_ADDRESS) { - goto invalid; - } - kprintf("frame 0x%x called by 0x%x ", - frame, frame->caller); - kprintf("args 0x%x 0x%x 0x%x 0x%x\n", - frame->args[0], frame->args[1], - frame->args[2], frame->args[3]); - if ((frame->prev < frame) || /* wrong direction */ - ((frame->prev - frame) > MAX_FRAME_DELTA)) { - goto invalid; - } - frame = frame->prev; - } - return; -invalid: - kprintf("invalid frame pointer 0x%x\n",frame); -} - -void +boolean_t kdp_i386_trap( unsigned int trapno, - struct i386_saved_state *saved_state, + x86_saved_state32_t *saved_state, kern_return_t result, vm_offset_t va ) { unsigned int exception, subcode = 0, code; + if (trapno != T_INT3 && trapno != T_DEBUG) { + kprintf("Debugger: Unexpected kernel trap number: " + "0x%x, EIP: 0x%x, CR2: 0x%x\n", + trapno, saved_state->eip, saved_state->cr2); + if (!kdp.is_conn) + return FALSE; + } + mp_kdp_enter(); + kdp_callouts(KDP_EVENT_ENTER); - if (trapno != T_INT3 && trapno != T_DEBUG) - kprintf("unexpected kernel trap 0x%x eip 0x%x cr2 0x%x \n", - trapno, saved_state->eip, saved_state->esp); + if (saved_state->efl & EFL_TF) { + enable_preemption_no_check(); + } switch (trapno) { @@ -463,11 +464,17 @@ kdp_i386_trap( break; } - kdp_i386_backtrace((void *) saved_state->ebp, 10); - kdp_raise_exception(exception, code, subcode, saved_state); + /* If the instruction single step bit is set, disable kernel preemption + */ + if (saved_state->efl & EFL_TF) { + disable_preemption(); + } + kdp_callouts(KDP_EVENT_EXIT); mp_kdp_exit(); + + return TRUE; } boolean_t @@ -477,8 +484,215 @@ kdp_call_kdb( return(FALSE); } -unsigned int -kdp_ml_get_breakinsn(void) +void +kdp_machine_get_breakinsn( + uint8_t *bytes, + uint32_t *size +) +{ + bytes[0] = 0xcc; + *size = 1; +} + +extern pmap_t kdp_pmap; + +#define RETURN_OFFSET 4 +int +machine_trace_thread(thread_t thread, char *tracepos, char *tracebound, int nframes, boolean_t user_p) +{ + uint32_t *tracebuf = (uint32_t *)tracepos; + uint32_t fence = 0; + uint32_t stackptr = 0; + uint32_t stacklimit = 0xfc000000; + int framecount = 0; + uint32_t init_eip = 0; + uint32_t prevsp = 0; + uint32_t framesize = 2 * sizeof(vm_offset_t); + + if (user_p) { + x86_saved_state32_t *iss32; + + iss32 = USER_REGS32(thread); + + init_eip = iss32->eip; + stackptr = iss32->ebp; + + /* This bound isn't useful, but it doesn't hinder us*/ + stacklimit = 0xffffffff; + kdp_pmap = thread->task->map->pmap; + } + else { + /*Examine the i386_saved_state at the base of the kernel stack*/ + stackptr = STACK_IKS(thread->kernel_stack)->k_ebp; + init_eip = STACK_IKS(thread->kernel_stack)->k_eip; + } + + *tracebuf++ = init_eip; + + for (framecount = 0; framecount < nframes; framecount++) { + + if ((uint32_t)(tracebound - ((char *)tracebuf)) < (4 * framesize)) { + tracebuf--; + break; + } + + *tracebuf++ = stackptr; +/* Invalid frame, or hit fence */ + if (!stackptr || (stackptr == fence)) { + break; + } + + /* Unaligned frame */ + if (stackptr & 0x0000003) { + break; + } + + if (stackptr > stacklimit) { + break; + } + + if (stackptr <= prevsp) { + break; + } + + if (kdp_machine_vm_read((mach_vm_address_t)(stackptr + RETURN_OFFSET), (caddr_t) tracebuf, sizeof(caddr_t)) != sizeof(caddr_t)) { + break; + } + tracebuf++; + + prevsp = stackptr; + if (kdp_machine_vm_read((mach_vm_address_t)stackptr, (caddr_t) &stackptr, sizeof(caddr_t)) != sizeof(caddr_t)) { + *tracebuf++ = 0; + break; + } + } + + kdp_pmap = 0; + + return (uint32_t) (((char *) tracebuf) - tracepos); +} + +#define RETURN_OFFSET64 8 +/* Routine to encapsulate the 64-bit address read hack*/ +unsigned +machine_read64(addr64_t srcaddr, caddr_t dstaddr, uint32_t len) +{ + return (unsigned)kdp_machine_vm_read(srcaddr, dstaddr, len); +} + +int +machine_trace_thread64(thread_t thread, char *tracepos, char *tracebound, int nframes, boolean_t user_p) +{ + uint64_t *tracebuf = (uint64_t *)tracepos; + uint32_t fence = 0; + addr64_t stackptr = 0; + uint64_t stacklimit = 0xfc000000; + int framecount = 0; + addr64_t init_rip = 0; + addr64_t prevsp = 0; + unsigned framesize = 2 * sizeof(addr64_t); + + if (user_p) { + x86_saved_state64_t *iss64; + iss64 = USER_REGS64(thread); + init_rip = iss64->isf.rip; + stackptr = iss64->rbp; + stacklimit = 0xffffffffffffffffULL; + kdp_pmap = thread->task->map->pmap; + } + + *tracebuf++ = init_rip; + + for (framecount = 0; framecount < nframes; framecount++) { + + if ((uint32_t)(tracebound - ((char *)tracebuf)) < (4 * framesize)) { + tracebuf--; + break; + } + + *tracebuf++ = stackptr; + + if (!stackptr || (stackptr == fence)){ + break; + } + + if (stackptr & 0x0000003) { + break; + } + if (stackptr > stacklimit) { + break; + } + + if (stackptr <= prevsp) { + break; + } + + if (machine_read64(stackptr + RETURN_OFFSET64, (caddr_t) tracebuf, sizeof(addr64_t)) != sizeof(addr64_t)) { + break; + } + tracebuf++; + + prevsp = stackptr; + if (machine_read64(stackptr, (caddr_t) &stackptr, sizeof(addr64_t)) != sizeof(addr64_t)) { + *tracebuf++ = 0; + break; + } + } + + kdp_pmap = NULL; + + return (uint32_t) (((char *) tracebuf) - tracepos); +} + +static struct kdp_callout { + struct kdp_callout *callout_next; + kdp_callout_fn_t callout_fn; + void *callout_arg; +} *kdp_callout_list = NULL; + + +/* + * Called from kernel context to register a kdp event callout. + */ +void +kdp_register_callout( + kdp_callout_fn_t fn, + void *arg) +{ + struct kdp_callout *kcp; + struct kdp_callout *list_head; + + kcp = kalloc(sizeof(*kcp)); + if (kcp == NULL) + panic("kdp_register_callout() kalloc failed"); + + kcp->callout_fn = fn; + kcp->callout_arg = arg; + + /* Lock-less list insertion using compare and exchange. */ + do { + list_head = kdp_callout_list; + kcp->callout_next = list_head; + } while (!OSCompareAndSwapPtr(list_head, kcp, (void * volatile *)&kdp_callout_list)); +} + +/* + * Called at exception/panic time when extering or exiting kdp. + * We are single-threaded at this time and so we don't use locks. + */ +static void +kdp_callouts(kdp_event_t event) +{ + struct kdp_callout *kcp = kdp_callout_list; + + while (kcp) { + kcp->callout_fn(kcp->callout_arg, event); + kcp = kcp->callout_next; + } +} + +void +kdp_ml_enter_debugger(void) { - return 0xcc; + __asm__ __volatile__("int3"); }