1/* 2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_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 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. 14 * 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 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 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. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28#include <mach/mach_types.h> 29#include <mach/vm_attributes.h> 30#include <mach/vm_param.h> 31#include <libsa/types.h> 32 33#include <kdp/kdp_core.h> 34#include <kdp/kdp_internal.h> 35#include <mach-o/loader.h> 36#include <mach/thread_status.h> 37#include <arm/thread.h> 38 39#include <mach/machine/vm_types.h> 40#include <arm/pmap.h> 41 42boolean_t kdp_trans_off; 43 44int kdp_dump_trap(int type, arm_saved_state_t * regs); 45 46static const arm_state_hdr_t thread_flavor_array[] = { 47 {ARM_THREAD_STATE, ARM_THREAD_STATE_COUNT} 48}; 49 50size_t kern_collectth_state_size(void) 51{ 52 unsigned int i; 53 size_t tstate_size = 0; 54 55 for (i = 0; i < sizeof(thread_flavor_array) / sizeof(thread_flavor_array[0]); i++) 56 tstate_size += sizeof(arm_state_hdr_t) + 57 (thread_flavor_array[i].count * sizeof(int)); 58 59 return tstate_size; 60} 61 62void kern_collectth_state(thread_t thread, void *buffer, size_t size) 63{ 64 size_t hoffset; 65 unsigned int i; 66 struct thread_command *tc; 67 68 /* 69 * Fill in thread command structure. 70 */ 71 hoffset = 0; 72 73 if (hoffset + sizeof(struct thread_command) > size) 74 return; 75 76 tc = (struct thread_command *) ((uintptr_t) buffer + hoffset); 77 tc->cmd = LC_THREAD; 78 tc->cmdsize = sizeof(struct thread_command) + kern_collectth_state_size(); 79 hoffset += sizeof(struct thread_command); 80 /* 81 * Follow with a struct thread_state_flavor and 82 * the appropriate thread state struct for each 83 * thread state flavor. 84 */ 85 for (i = 0; i < sizeof(thread_flavor_array) / sizeof(thread_flavor_array[0]); i++) { 86 87 if (hoffset + sizeof(arm_state_hdr_t) > size) 88 return; 89 90 *(arm_state_hdr_t *) ((uintptr_t) buffer + hoffset) = thread_flavor_array[i]; 91 hoffset += sizeof(arm_state_hdr_t); 92 93 if (hoffset + thread_flavor_array[i].count * sizeof(int) > size) 94 return; 95 96 /* 97 * Locate and obtain the non-volatile register context 98 * * for this kernel thread. This should ideally be 99 * * encapsulated in machine_thread_get_kern_state() 100 * * but that routine appears to have been co-opted 101 * * by CHUD to obtain pre-interrupt state. 102 */ 103 if (thread_flavor_array[i].flavor == ARM_THREAD_STATE) { 104 arm_thread_state_t *tstate = 105 (arm_thread_state_t *) ((uintptr_t) buffer + hoffset); 106 vm_offset_t kstack; 107 108 bzero(tstate, ARM_THREAD_STATE_COUNT * sizeof(int)); 109 // broken 110 } else { 111 void *tstate = (void *) ((uintptr_t) buffer + hoffset); 112 113 bzero(tstate, thread_flavor_array[i].count * sizeof(int)); 114 } 115 116 hoffset += thread_flavor_array[i].count * sizeof(int); 117 } 118} 119 120/* 121 * 122 */ 123static addr64_t kdp_vtophys(pmap_t pmap, addr64_t va) 124{ 125 addr64_t pa; 126 ppnum_t pp; 127 128 pp = pmap_find_phys_fvtp(pmap, va); /* Get the page number */ 129 if (!pp) 130 return 0; /* Just return if no translation */ 131 132 pa = ((addr64_t) pp << 12) | (va & 0x0000000000000FFFULL); /* Shove in the page offset */ 133 return (pa); 134} 135 136/* Intended to be called from the kernel trap handler if an unrecoverable fault 137 * occurs during a crashdump (which shouldn't happen since we validate mappings 138 * and so on). This should be reworked to attempt some form of recovery. 139 */ 140int kdp_dump_trap(int type, __unused arm_saved_state_t * saved_state) 141{ 142 printf("An unexpected trap (type %d) occurred during the system dump, terminating.\n", 143 type); 144 kdp_send_crashdump_pkt(KDP_EOF, NULL, 0, ((void *) 0)); 145 abort_panic_transfer(); 146 kdp_flag &= ~KDP_PANIC_DUMP_ENABLED; 147 kdp_flag &= ~PANIC_CORE_ON_NMI; 148 kdp_flag &= ~PANIC_LOG_DUMP; 149 150 kdp_reset(); 151 152 kdp_raise_exception(EXC_BAD_ACCESS, 0, 0, kdp.saved_state); 153 return (0); 154} 155 156mach_vm_size_t kdp_machine_vm_read(mach_vm_address_t src, caddr_t dst, mach_vm_size_t len) 157{ 158 addr64_t cur_virt_src, cur_virt_dst; 159 addr64_t cur_phys_src, cur_phys_dst; 160 unsigned resid, cnt; 161 unsigned int dummy; 162 pmap_t pmap; 163 164#if 0 165 kprintf("kdp_machine_vm_read1: src %llx dst %llx len %x - %08X %08X\n", src, dst, len, 166 ((unsigned long *) src)[0], ((unsigned long *) src)[1]); 167#endif 168 169 cur_virt_src = (addr64_t) src; 170 cur_virt_dst = (addr64_t) (intptr_t) dst; 171 172 if (kdp_trans_off) { 173 resid = len; /* Get the length to copy */ 174 175 while (resid != 0) { 176 177 if ((cur_phys_dst = kdp_vtophys(kernel_pmap, cur_virt_dst)) == 0) 178 goto exit; 179 180 cnt = 4096 - (cur_virt_src & 0xFFF); /* Get length left on page */ 181 if (cnt > (4096 - (cur_virt_dst & 0xFFF))) 182 cnt = 4096 - (cur_virt_dst & 0xFFF); 183 184 if (cnt > resid) 185 cnt = resid; 186 187 bcopy_phys(cur_virt_src, cur_phys_dst, cnt); /* Copy stuff over */ 188 189 cur_virt_src += cnt; 190 cur_virt_dst += cnt; 191 resid -= cnt; 192 } 193 194 } else { 195 196 resid = len; 197 198 while (resid != 0) { 199 /* 200 * Always translate the destination using the kernel_pmap. 201 */ 202 if ((cur_phys_dst = kdp_vtophys(kernel_pmap, cur_virt_dst)) == 0) 203 goto exit; 204 205 if ((cur_phys_src = kdp_vtophys(kernel_pmap, cur_virt_src)) == 0) 206 goto exit; 207 208 cnt = 4096 - (cur_virt_src & 0xFFF); /* Get length left on page */ 209 if (cnt > (4096 - (cur_virt_dst & 0xFFF))) 210 cnt = 4096 - (cur_virt_dst & 0xFFF); 211 212 if (cnt > resid) 213 cnt = resid; 214 215#if 0 216 kprintf("kdp_machine_vm_read2: pmap %08X, virt %016LLX, phys %016LLX\n", 217 pmap, cur_virt_src, cur_phys_src); 218#endif 219 220 bcopy_phys(cur_phys_src, cur_phys_dst, cnt); /* Copy stuff over */ 221 222 cur_virt_src += cnt; 223 cur_virt_dst += cnt; 224 resid -= cnt; 225 } 226 } 227 exit: 228#if 0 229 kprintf("kdp_machine_vm_read: ret %08X\n", len - resid); 230#endif 231 return (len - resid); 232} 233 234mach_vm_size_t 235kdp_machine_phys_read(kdp_readphysmem64_req_t * rq __unused, caddr_t dst __unused, 236 uint16_t lcpu __unused) 237{ 238 return 0; /* unimplemented */ 239} 240 241mach_vm_size_t 242kdp_machine_phys_write(kdp_writephysmem64_req_t * rq __unused, caddr_t src __unused, 243 uint16_t lcpu __unused) 244{ 245 return 0; /* unimplemented */ 246} 247 248mach_vm_size_t 249kdp_machine_vm_write(caddr_t src, mach_vm_address_t dst, mach_vm_size_t len) 250{ 251 addr64_t cur_virt_src, cur_virt_dst; 252 addr64_t cur_phys_src, cur_phys_dst; 253 unsigned resid, cnt; 254 unsigned int dummy; 255 pmap_t pmap; 256 257 cur_virt_src = (addr64_t) src; 258 cur_virt_dst = (addr64_t) (intptr_t) dst; 259 260 if (kdp_trans_off) { 261 return 0; 262 } else { 263 resid = len; 264 while (resid != 0) { 265 /* 266 * Always translate the destination using the kernel_pmap. 267 */ 268 if ((cur_phys_dst = kdp_vtophys(kernel_pmap, cur_virt_dst)) == 0) 269 goto exit; 270 271 if ((cur_phys_src = kdp_vtophys(kernel_pmap, cur_virt_src)) == 0) 272 goto exit; 273 274 cnt = 4096 - (cur_virt_src & 0xFFF); /* Get length left on page */ 275 if (cnt > (4096 - (cur_virt_dst & 0xFFF))) 276 cnt = 4096 - (cur_virt_dst & 0xFFF); 277 278 if (cnt > resid) 279 cnt = resid; 280 281 bcopy_phys(cur_phys_src, cur_phys_dst, cnt); /* Copy stuff over */ 282 283 cur_virt_src += cnt; 284 cur_virt_dst += cnt; 285 resid -= cnt; 286 } 287 } 288 exit: 289#if 0 290 kprintf("kdp_machine_vm_read: ret %08X\n", len - resid); 291#endif 292 return (len - resid); 293} 294