]>
Commit | Line | Data |
---|---|---|
5ba3f43e A |
1 | /* |
2 | * Copyright (c) 2012 Apple Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ | |
0a7de745 | 5 | * |
5ba3f43e 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. | |
0a7de745 | 14 | * |
5ba3f43e A |
15 | * Please obtain a copy of the License at |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
0a7de745 | 17 | * |
5ba3f43e A |
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. | |
0a7de745 | 25 | * |
5ba3f43e A |
26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ |
27 | */ | |
28 | ||
29 | #if ALTERNATE_DEBUGGER | |
30 | ||
31 | /* | |
0a7de745 A |
32 | * |
33 | * The alternate debugger feature is enabled by setting the boot arg "alternate_debugger_init" | |
34 | * to the size of memory that should be set aside for the debugger. The boot arg | |
35 | * "alternate_debugger_init_pages" is used to allocate more vmpages that the alternate debugger | |
36 | * may use to do additional VA->PA mappings. The boot-arg "alternate_debugger_pause_for_load_at_boot" | |
37 | * will halt the system so that the debugger can be loaded early in the boot cycle -- once the | |
38 | * alternate debugger code is loaded, a register must be set to a 1 to continue the boot process. | |
39 | * | |
40 | * Here's an example: | |
41 | * nvram boot-arg="alternate_debugger_init=0x800000 alternate_debugger_init_pages=0x8000 alternate_debugger_pause_for_load_at_boot=1" | |
42 | * | |
43 | * The low memory global lgAltDebugger will contain the address of the allocated memory for | |
44 | * the alternate debugger. On arm64, the address of this low memory global is 0xffffff8000002048. | |
45 | * | |
46 | * At any point after the low memory global is non-zero, Astris may be used to halt the cpu | |
47 | * and load the alternate debugger: | |
48 | * | |
49 | * If no alternate debugger is given, but alternate_debugger_init has been specified, and the | |
50 | * kernel debugger is entered, the string ">MT<" is printed and normal processing continues. | |
51 | * | |
52 | * Anytime the alternate debugger is entered, the osversion string is modified to start with "ALT" | |
53 | * so that panic reports can clearly indicated that some kernel poking may have occurred, and | |
54 | * the panic should be weighted accordingly. | |
55 | * | |
56 | */ | |
5ba3f43e A |
57 | |
58 | #include <arm64/alternate_debugger.h> | |
59 | ||
60 | #include <kern/kalloc.h> | |
61 | #include <arm64/lowglobals.h> | |
62 | #include <arm/caches_internal.h> | |
63 | #include <kern/cpu_data.h> | |
64 | #include <arm/pmap.h> | |
65 | #include <pexpert/pexpert.h> | |
66 | #include <vm/vm_map.h> | |
67 | #include <vm/vm_kern.h> | |
68 | #include <libkern/version.h> | |
69 | ||
70 | void kprintf(const char *fmt, ...); | |
71 | ||
72 | ||
73 | static mach_vm_address_t alt_code; | |
74 | static mach_vm_size_t alt_size; | |
75 | static mach_vm_address_t alt_pages; | |
76 | static mach_vm_size_t alt_pages_size; | |
77 | ||
78 | typedef void (*t_putc_fn)(char c); | |
79 | typedef void (*t_call_altdbg_fn)(mach_vm_size_t size, mach_vm_address_t pages, mach_vm_size_t pages_size, t_putc_fn putc_address ); | |
80 | ||
0a7de745 | 81 | // used as a temporary alternate debugger until another is loaded |
5ba3f43e A |
82 | extern void alternate_debugger_just_return(__unused mach_vm_size_t size, __unused mach_vm_address_t pages, __unused mach_vm_size_t pages_size, t_putc_fn putc_address); |
83 | extern void *alternate_debugger_just_return_end; | |
84 | ||
85 | // public entry to the alternate debugger | |
0a7de745 A |
86 | void |
87 | alternate_debugger_enter(void) | |
5ba3f43e | 88 | { |
0a7de745 | 89 | if (alt_code != 0) { |
5ba3f43e A |
90 | disable_preemption(); |
91 | ||
92 | printf("########## Going to call ALTERNATE DEBUGGER\n"); | |
93 | ||
94 | // make sure it isn't in the cache | |
95 | assert((alt_size & 0xFFFFFFFF00000000) == 0); | |
96 | flush_dcache(alt_code, (unsigned int)alt_size, 0); | |
97 | ||
98 | // set the code to execute | |
0a7de745 | 99 | pmap_protect(kernel_map->pmap, alt_code, alt_code + alt_size, VM_PROT_READ | VM_PROT_EXECUTE); |
5ba3f43e A |
100 | |
101 | // black-spot the OS version for any panic reports that occur because of entering the alternate debugger | |
0a7de745 | 102 | if (*osversion) { |
5ba3f43e A |
103 | memcpy(osversion, "ALT", 3); // Version set, stomp on the begining of it |
104 | } else { | |
105 | strncpy(osversion, "ALT - Version Not Set Yet", OSVERSIZE); | |
106 | } | |
107 | ||
108 | kprintf("########## Calling ALTERNATE DEBUGGER (size %lld, pages 0x%llx, pages_size 0x%llx, putc %p\n", alt_size, alt_pages, alt_pages_size, &consdebug_putc_unbuffered); | |
109 | ((t_call_altdbg_fn)alt_code)(alt_size, alt_pages, alt_pages_size, &consdebug_putc_unbuffered); | |
110 | kprintf("########## Returned from calling ALTERNATE DEBUGGER\n"); | |
111 | ||
112 | enable_preemption(); | |
113 | } | |
114 | } | |
115 | ||
116 | // public entry to check boot args and init accordingly | |
0a7de745 A |
117 | void |
118 | alternate_debugger_init(void) | |
5ba3f43e A |
119 | { |
120 | // use the alternate debugger | |
0a7de745 | 121 | if (PE_parse_boot_argn("alternate_debugger_init", (void*)&alt_size, sizeof(alt_size))) { |
5ba3f43e A |
122 | vm_offset_t alt_va = 0; |
123 | ||
124 | kprintf("########## ALTERNATE_DEBUGGER\n"); | |
125 | ||
126 | PE_parse_boot_argn("alternate_debugger_init_pages", (void*)&alt_pages_size, sizeof(alt_pages_size)); | |
127 | ||
128 | alt_size = vm_map_round_page(alt_size, | |
0a7de745 | 129 | VM_MAP_PAGE_MASK(kernel_map)); |
5ba3f43e | 130 | alt_pages_size = vm_map_round_page(alt_pages_size, |
0a7de745 | 131 | VM_MAP_PAGE_MASK(kernel_map)); |
5ba3f43e A |
132 | |
133 | kern_return_t kr = KERN_SUCCESS; | |
134 | kr = kmem_alloc_contig(kernel_map, &alt_va, alt_size, VM_MAP_PAGE_MASK(kernel_map), 0, 0, KMA_NOPAGEWAIT | KMA_KOBJECT | KMA_LOMEM, VM_KERN_MEMORY_DIAG); | |
0a7de745 | 135 | if (kr != KERN_SUCCESS) { |
5ba3f43e A |
136 | kprintf("########## ALTERNATE_DEBUGGER FAILED kmem_alloc_contig with %d\n", kr); |
137 | alt_va = 0; | |
0a7de745 A |
138 | } else { |
139 | if (alt_pages_size) { | |
5ba3f43e A |
140 | alt_pages = (vm_offset_t) kalloc((vm_size_t) alt_pages_size); |
141 | } | |
142 | } | |
143 | ||
144 | kprintf("########## Initializing ALTERNATE DEBUGGER : [alloc size 0x%llx @0x%lx] [pages_size 0x%llx @0x%llx] -- lowmem pointer at %p\n", | |
0a7de745 | 145 | alt_size, alt_va, alt_pages_size, alt_pages, &lowGlo.lgAltDebugger ); |
5ba3f43e | 146 | |
0a7de745 | 147 | if (alt_va) { |
5ba3f43e A |
148 | uintptr_t just_return_size = (uintptr_t)&alternate_debugger_just_return_end - (uintptr_t)&alternate_debugger_just_return; |
149 | assert(just_return_size <= alt_size); // alt_size is page-rounded, just_return_size should be much less than a page. | |
150 | // install a simple return vector | |
151 | memcpy((void*)alt_va, &alternate_debugger_just_return, just_return_size); | |
152 | ||
153 | // code is ready, enable the pointers to it | |
154 | lowGlo.lgAltDebugger = alt_code = alt_va; | |
155 | ||
156 | #if 1 | |
157 | // DEBUG for BRING-UP testing | |
158 | unsigned int alt_init_test; | |
0a7de745 | 159 | if (PE_parse_boot_argn("alternate_debugger_pause_for_load_at_boot", &alt_init_test, sizeof(alt_init_test))) { |
5ba3f43e A |
160 | // debug!! |
161 | kprintf("########## Waiting for ALTERNATE DEBUGGER to load (in file %s).... to continue, set register to 1", __FILE__ ); | |
162 | volatile int ii = 0; | |
0a7de745 | 163 | while (!ii) { |
5ba3f43e | 164 | ; |
0a7de745 | 165 | } |
5ba3f43e A |
166 | kprintf("\n"); |
167 | alternate_debugger_enter(); | |
168 | } | |
169 | #endif | |
170 | } | |
171 | } | |
172 | } | |
173 | ||
174 | #endif /* ALTERNATE_DEBUGGER */ |