1/* 2 * Copyright (c) 2009 Apple Inc. All rights reserved. 3 * 4 * @APPLE_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. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24/* 25 * Copyright 2013, winocm. <winocm@icloud.com> 26 * All rights reserved. 27 * 28 * Redistribution and use in source and binary forms, with or without modification, 29 * are permitted provided that the following conditions are met: 30 * 31 * Redistributions of source code must retain the above copyright notice, this 32 * list of conditions and the following disclaimer. 33 * 34 * Redistributions in binary form must reproduce the above copyright notice, this 35 * list of conditions and the following disclaimer in the documentation and/or 36 * other materials provided with the distribution. 37 * 38 * If you are going to use this software in any form that does not involve 39 * releasing the source to this project or improving it, let me know beforehand. 40 * 41 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 42 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 43 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 44 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 45 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 46 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 47 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 48 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 49 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 50 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 51 */ 52 53/* 54 * ARM machine startup functions 55 */ 56 57#include <platforms.h> 58#include <mach/arm/vm_param.h> 59#include <string.h> 60#include <sys/time.h> 61#include <mach/vm_param.h> 62#include <mach/vm_prot.h> 63#include <mach/machine.h> 64#include <mach/time_value.h> 65#include <kern/spl.h> 66#include <kern/assert.h> 67#include <kern/debug.h> 68#include <kern/misc_protos.h> 69#include <kern/startup.h> 70#include <kern/clock.h> 71#include <kern/cpu_data.h> 72#include <kern/machine.h> 73#include <arm/pmap.h> 74 75#include <mach_debug.h> 76#include <arm/low_globals.h> 77 78#include <arm/misc_protos.h> 79 80#include <pexpert/pexpert.h> 81#include <pexpert/arm/boot.h> 82 83#include <vm/pmap.h> 84#include <vm/vm_map.h> 85#include <vm/vm_kern.h> 86 87#include <kern/thread.h> 88#include <kern/sched.h> 89#include <mach-o/loader.h> 90#include <mach-o/nlist.h> 91 92#include <arm/arch.h> 93 94#include <libkern/kernel_mach_header.h> 95#include <libkern/OSKextLibPrivate.h> 96 97#include <IOKit/IOPlatformExpert.h> 98 99extern unsigned int panic_is_inited; 100extern struct timeval gIOLastSleepTime; 101extern struct timeval gIOLastWakeTime; 102extern char firmware_version[32]; 103extern uint32_t debug_enabled; 104extern const char version[]; 105extern char osversion[]; 106extern boolean_t panicDialogDesired; 107extern int enable_timing; 108 109#define ANSI_COLOR_RED "\x1b[31m" 110#define ANSI_COLOR_GREEN "\x1b[32m" 111#define ANSI_COLOR_YELLOW "\x1b[33m" 112#define ANSI_COLOR_BLUE "\x1b[34m" 113#define ANSI_COLOR_MAGENTA "\x1b[35m" 114#define ANSI_COLOR_CYAN "\x1b[36m" 115#define ANSI_COLOR_RESET "\x1b[0m" 116 117/* 118 * Frame pointer definition. 119 */ 120 121typedef struct _cframe_t { 122 struct _cframe_t *prev; 123 uintptr_t caller; 124} cframe_t; 125 126unsigned int nosym = 1; 127 128void print_threads(uint32_t stackptr); 129void panic_arm_thread_backtrace(void *_frame, int nframes, const char *msg, 130 boolean_t regdump, arm_saved_state_t * regs, 131 int crashed, char *crashstr); 132 133/** 134 * machine_init 135 * 136 * Machine-specific initialization. 137 */ 138void machine_init(void) 139{ 140 debug_log_init(); 141 clock_config(); 142 return; 143} 144 145static void machine_conf(void) 146{ 147 machine_info.memory_size = (typeof(machine_info.memory_size)) mem_size; 148 machine_info.max_mem = (typeof(machine_info.max_mem)) max_mem; 149} 150 151unsigned int debug_boot_arg; 152 153/* 154 * Debugger/DebuggerWithContext. 155 * 156 * Back to plagiarizing from i386. 157 */ 158 159/* Routines for address - symbol translation. Not called unless the "keepsyms" 160 * boot-arg is supplied. 161 */ 162 163static int 164panic_print_macho_symbol_name(kernel_mach_header_t *mh, vm_address_t search, const char *module_name) 165{ 166 kernel_nlist_t *sym = NULL; 167 struct load_command *cmd; 168 kernel_segment_command_t *orig_ts = NULL, *orig_le = NULL; 169 struct symtab_command *orig_st = NULL; 170 unsigned int i; 171 char *strings, *bestsym = NULL; 172 vm_address_t bestaddr = 0, diff, curdiff; 173 174 /* Assume that if it's loaded and linked into the kernel, it's a valid Mach-O */ 175 176 cmd = (struct load_command *) &mh[1]; 177 for (i = 0; i < mh->ncmds; i++) { 178 if (cmd->cmd == LC_SEGMENT_KERNEL) { 179 kernel_segment_command_t *orig_sg = (kernel_segment_command_t *) cmd; 180 181 if (strncmp(SEG_TEXT, orig_sg->segname, 182 sizeof(orig_sg->segname)) == 0) 183 orig_ts = orig_sg; 184 else if (strncmp(SEG_LINKEDIT, orig_sg->segname, 185 sizeof(orig_sg->segname)) == 0) 186 orig_le = orig_sg; 187 else if (strncmp("", orig_sg->segname, 188 sizeof(orig_sg->segname)) == 0) 189 orig_ts = orig_sg; /* pre-Lion i386 kexts have a single unnamed segment */ 190 } 191 else if (cmd->cmd == LC_SYMTAB) 192 orig_st = (struct symtab_command *) cmd; 193 194 cmd = (struct load_command *) ((uintptr_t) cmd + cmd->cmdsize); 195 } 196 197 if ((orig_ts == NULL) || (orig_st == NULL) || (orig_le == NULL)) 198 return 0; 199 200 if ((search < orig_ts->vmaddr) || 201 (search >= orig_ts->vmaddr + orig_ts->vmsize)) { 202 /* search out of range for this mach header */ 203 return 0; 204 } 205 206 sym = (kernel_nlist_t *)(uintptr_t)(orig_le->vmaddr + orig_st->symoff - orig_le->fileoff); 207 strings = (char *)(uintptr_t)(orig_le->vmaddr + orig_st->stroff - orig_le->fileoff); 208 diff = search; 209 210 for (i = 0; i < orig_st->nsyms; i++) { 211 if (sym[i].n_type & N_STAB) continue; 212 213 if (sym[i].n_value <= search) { 214 curdiff = search - (vm_address_t)sym[i].n_value; 215 if (curdiff < diff) { 216 diff = curdiff; 217 bestaddr = sym[i].n_value; 218 bestsym = strings + sym[i].n_un.n_strx; 219 } 220 } 221 } 222 223 if (bestsym != NULL) { 224 if (diff != 0) { 225 kdb_printf("%s : %s + 0x%lx", module_name, bestsym, (unsigned long)diff); 226 } else { 227 kdb_printf("%s : %s", module_name, bestsym); 228 } 229 return 1; 230 } 231 return 0; 232} 233 234extern kmod_info_t * kmod; /* the list of modules */ 235 236static void 237panic_print_kmod_symbol_name(vm_address_t search) 238{ 239 u_int i; 240 241 if (gLoadedKextSummaries == NULL) 242 return; 243 for (i = 0; i < gLoadedKextSummaries->numSummaries; ++i) { 244 OSKextLoadedKextSummary *summary = gLoadedKextSummaries->summaries + i; 245 246 if ((search >= summary->address) && 247 (search < (summary->address + summary->size))) 248 { 249 kernel_mach_header_t *header = (kernel_mach_header_t *)(uintptr_t) summary->address; 250 if (panic_print_macho_symbol_name(header, search, summary->name) == 0) { 251 kdb_printf("%s + %llu", summary->name, (unsigned long)search - summary->address); 252 } 253 break; 254 } 255 } 256} 257 258static void 259panic_print_symbol_name(vm_address_t search) 260{ 261 /* try searching in the kernel */ 262 if (panic_print_macho_symbol_name(&_mh_execute_header, search, "mach_kernel") == 0) { 263 /* that failed, now try to search for the right kext */ 264 panic_print_kmod_symbol_name(search); 265 } 266} 267 268/* Generate a backtrace, given a frame pointer - this routine 269 * should walk the stack safely. The trace is appended to the panic log 270 * and conditionally, to the console. If the trace contains kernel module 271 * addresses, display the module name, load address and dependencies. 272 */ 273 274#define DUMPFRAMES 32 275#define PBT_TIMEOUT_CYCLES (5 * 1000 * 1000 * 1000ULL) 276void 277panic_arm_backtrace(void *_frame, int nframes, const char *msg, boolean_t regdump, arm_saved_state_t *regs) 278{ 279 cframe_t *frame = (cframe_t *)_frame; 280 vm_offset_t raddrs[DUMPFRAMES]; 281 vm_offset_t PC = 0; 282 int frame_index; 283 boolean_t keepsyms = FALSE; 284 int cn = cpu_number(); 285 286 PE_parse_boot_argn("keepsyms", &keepsyms, sizeof (keepsyms)); 287 288 if (msg != NULL) { 289 kdb_printf("%s", msg); 290 } 291 292 kdb_printf("Backtrace (CPU %d), " 293 "Frame : Return Address\n", cn); 294 295 for (frame_index = 0; frame_index < nframes; frame_index++) { 296 vm_offset_t curframep = (vm_offset_t) frame; 297 298 if (!curframep) 299 break; 300 301 if (curframep & 0x3) { 302 kdb_printf("Unaligned frame\n"); 303 goto invalid; 304 } 305 306 if (!kvtophys(curframep) || 307 !kvtophys(curframep + sizeof(cframe_t) - 1)) { 308 kdb_printf("No mapping exists for frame pointer\n"); 309 goto invalid; 310 } 311 312 kdb_printf("%p : 0x%lx ", frame, frame->caller); 313 if (frame_index < DUMPFRAMES) 314 raddrs[frame_index] = frame->caller; 315 316 /* Display address-symbol translation only if the "keepsyms" 317 * boot-arg is suppplied, since we unload LINKEDIT otherwise. 318 * This routine is potentially unsafe; also, function 319 * boundary identification is unreliable after a strip -x. 320 * 321 * Right now, OSKextRemoveKextBootstrap is nulled out, so it 322 * doesn't really matter at the moment. Dofix. 323 */ 324#if 0 325 if (keepsyms) 326#endif 327 panic_print_symbol_name((vm_address_t)frame->caller); 328 329 kdb_printf("\n"); 330 331 frame = frame->prev; 332 } 333 334 if (frame_index >= nframes) 335 kdb_printf("\tBacktrace continues...\n"); 336 337 goto out; 338 339invalid: 340 kdb_printf("Backtrace terminated-invalid frame pointer %p\n",frame); 341out: 342 343 /* Identify kernel modules in the backtrace and display their 344 * load addresses and dependencies. This routine should walk 345 * the kmod list safely. 346 */ 347 if (frame_index) 348 kmod_panic_dump((vm_offset_t *)&raddrs[0], frame_index); 349 350 if (PC != 0) 351 kmod_panic_dump(&PC, 1); 352 353 panic_display_system_configuration(); 354} 355 356 357void 358DebuggerWithContext( 359 __unused unsigned int reason, 360 __unused void *ctx, 361 const char *message) 362{ 363 Debugger(message); 364} 365 366void 367Debugger( 368 const char *message) 369{ 370 unsigned long pi_size = 0; 371 void *stackptr; 372 int cn = cpu_number(); 373 374 hw_atomic_add(&debug_mode, 1); 375 if (!panic_is_inited) { 376 /* Halt forever. */ 377#ifdef _ARM_ARCH_7 378 asm("cpsid if; wfi; b ."); 379#else 380 asm("cpsid if; b ."); 381#endif 382 } 383 384 printf("Debugger called: <%s>\n", message); 385 kprintf("Debugger called: <%s>\n", message); 386 387 /* 388 * Skip the graphical panic box if no panic string. 389 * This is the case if we're being called from 390 * host_reboot(,HOST_REBOOT_DEBUGGER) 391 * as a quiet way into the debugger. 392 */ 393 394 if (panicstr) { 395 disable_preemption(); 396 397 /* Obtain current frame pointer */ 398#if defined (__arm__) 399 __asm__ volatile("mov %0, r7" : "=r" (stackptr)); 400#endif 401 402 /* Print backtrace - callee is internally synchronized */ 403 panic_arm_backtrace(stackptr, 48, NULL, FALSE, NULL); 404 405 /* Draw panic dialog if needed */ 406 draw_panic_dialog(); 407 } 408 409 /* Enter KDP if necessary. */ 410 if(current_debugger) 411 __asm__ __volatile__("bkpt #0"); 412 413 hw_atomic_sub(&debug_mode, 1); 414} 415 416#define VECTORS_BASE 0xFFFF0000 417 418/* 419 * VBARNS support will break kdp for now. 420 */ 421lowglo* lowGlo = (lowglo*)VECTORS_BASE; 422 423extern void *flag_kdp_trigger_reboot; 424extern void *manual_pkt; 425 426/** 427 * machine_startup 428 * 429 * Configure core kernel variables and go to Mach kernel bootstrap. 430 */ 431void machine_startup(void) 432{ 433 machine_conf(); 434 435 if (PE_parse_boot_argn("debug", &debug_boot_arg, sizeof(debug_boot_arg))) { 436 panicDebugging = TRUE; 437 if (debug_boot_arg & DB_HALT) 438 halt_in_debugger = 1; 439 if (debug_boot_arg & DB_PRT) 440 disable_debug_output = FALSE; 441 if (debug_boot_arg & DB_SLOG) 442 systemLogDiags = TRUE; 443 if (debug_boot_arg & DB_LOG_PI_SCRN) 444 logPanicDataToScreen = TRUE; 445 446 /* 447 * Set up low globals 448 */ 449 lowGlo->lgOSVersion = (uint32_t) version; 450 lowGlo->lgRebootFlag = (uint32_t) &flag_kdp_trigger_reboot; 451 lowGlo->lgManualPacket = (uint32_t) &manual_pkt; 452 } else { 453 debug_boot_arg = 0; 454 } 455 456 /* 457 * Cause a breakpoint trap to the debugger before proceeding 458 * any further if the proper option bit was specified in 459 * the boot flags. 460 */ 461 if (halt_in_debugger) { 462 Debugger("inline call to debugger(machine_startup)"); 463 halt_in_debugger = 0; 464 active_debugger = 1; 465 } 466 467 kernel_bootstrap(); 468 return; 469} 470 471/** 472 * machine_boot_info 473 * 474 * Return string of boot args passed to kernel. 475 */ 476char *machine_boot_info(char *buf, vm_size_t size) 477{ 478 return (PE_boot_args()); 479} 480 481/** 482 * mach_syscall_trace 483 */ 484extern const char *mach_syscall_name_table[]; 485void mach_syscall_trace(arm_saved_state_t * state) 486{ 487 488} 489 490/* 491 * Halt a cpu. 492 */ 493void halt_cpu(void) 494{ 495 halt_all_cpus(FALSE); 496} 497 498int reset_mem_on_reboot = 1; 499/* 500 * Halt the system or reboot. 501 */ 502void halt_all_cpus(boolean_t reboot) 503{ 504 if (reboot) { 505 printf("MACH Reboot\n"); 506 if (PE_halt_restart) 507 (*PE_halt_restart) (kPERestartCPU); 508 } else { 509 printf("CPU halted\n"); 510 if (PE_halt_restart) 511 (*PE_halt_restart) (kPEHaltCPU); 512 } 513 while (1) ; 514} 515