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