]>
Commit | Line | Data |
---|---|---|
1c79356b | 1 | /* |
2d21ac55 | 2 | * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved. |
1c79356b | 3 | * |
2d21ac55 | 4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ |
1c79356b | 5 | * |
2d21ac55 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. | |
8f6c56a5 | 14 | * |
2d21ac55 A |
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 | |
8f6c56a5 A |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
2d21ac55 A |
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. | |
8f6c56a5 | 25 | * |
2d21ac55 | 26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ |
1c79356b A |
27 | */ |
28 | /* | |
29 | * @OSF_COPYRIGHT@ | |
30 | */ | |
31 | /* | |
32 | * Mach Operating System | |
33 | * Copyright (c) 1991,1990,1989, 1988 Carnegie Mellon University | |
34 | * All Rights Reserved. | |
35 | * | |
36 | * Permission to use, copy, modify and distribute this software and its | |
37 | * documentation is hereby granted, provided that both the copyright | |
38 | * notice and this permission notice appear in all copies of the | |
39 | * software, derivative works or modified versions, and any portions | |
40 | * thereof, and that both notices appear in supporting documentation. | |
41 | * | |
42 | * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" | |
43 | * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR | |
44 | * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. | |
45 | * | |
46 | * Carnegie Mellon requests users of this software to return to | |
47 | * | |
48 | * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU | |
49 | * School of Computer Science | |
50 | * Carnegie Mellon University | |
51 | * Pittsburgh PA 15213-3890 | |
52 | * | |
53 | * any improvements or extensions that they make and grant Carnegie Mellon | |
54 | * the rights to redistribute these changes. | |
55 | */ | |
56 | ||
57 | /* | |
58 | */ | |
59 | ||
60 | /* | |
61 | * File: model_dep.c | |
62 | * Author: Avadis Tevanian, Jr., Michael Wayne Young | |
63 | * | |
64 | * Copyright (C) 1986, Avadis Tevanian, Jr., Michael Wayne Young | |
65 | * | |
66 | * Basic initialization for I386 - ISA bus machines. | |
67 | */ | |
68 | ||
1c79356b | 69 | #include <platforms.h> |
1c79356b | 70 | #include <mach_kdb.h> |
1c79356b A |
71 | |
72 | #include <mach/i386/vm_param.h> | |
73 | ||
74 | #include <string.h> | |
75 | #include <mach/vm_param.h> | |
76 | #include <mach/vm_prot.h> | |
77 | #include <mach/machine.h> | |
78 | #include <mach/time_value.h> | |
1c79356b A |
79 | #include <kern/spl.h> |
80 | #include <kern/assert.h> | |
81 | #include <kern/debug.h> | |
82 | #include <kern/misc_protos.h> | |
83 | #include <kern/startup.h> | |
84 | #include <kern/clock.h> | |
1c79356b | 85 | #include <kern/cpu_data.h> |
91447636 | 86 | #include <kern/machine.h> |
1c79356b | 87 | #include <i386/fpu.h> |
1c79356b | 88 | #include <i386/ipl.h> |
1c79356b | 89 | #include <i386/misc_protos.h> |
91447636 | 90 | #include <i386/mtrr.h> |
0c530ab8 A |
91 | #include <i386/machine_routines.h> |
92 | #include <i386/pmCPU.h> | |
91447636 | 93 | #include <i386/postcode.h> |
2d21ac55 A |
94 | #include <i386/trap.h> |
95 | #include <i386/mp.h> /* mp_rendezvous_break_lock */ | |
0c530ab8 | 96 | #include <architecture/i386/pio.h> /* inb() */ |
55e303ae | 97 | #include <pexpert/i386/boot.h> |
1c79356b A |
98 | #if MACH_KDB |
99 | #include <ddb/db_aout.h> | |
100 | #endif /* MACH_KDB */ | |
1c79356b | 101 | |
0c530ab8 A |
102 | #include <vm/pmap.h> |
103 | #include <vm/vm_map.h> | |
104 | #include <vm/vm_kern.h> | |
105 | ||
1c79356b | 106 | #include <i386/mp_desc.h> |
55e303ae | 107 | #include <i386/mp.h> |
0c530ab8 | 108 | #include <i386/cpuid.h> |
1c79356b | 109 | |
9bccf70c | 110 | #include <IOKit/IOPlatformExpert.h> |
0c530ab8 A |
111 | #include <IOKit/IOHibernatePrivate.h> |
112 | ||
113 | #include <pexpert/i386/efi.h> | |
114 | ||
115 | #include <kern/thread.h> | |
116 | #include <i386/thread.h> | |
117 | #include <mach-o/loader.h> | |
118 | #include <mach-o/nlist.h> | |
9bccf70c | 119 | |
91447636 A |
120 | void enable_bluebox(void); |
121 | void disable_bluebox(void); | |
122 | ||
55e303ae | 123 | static void machine_conf(void); |
1c79356b | 124 | |
91447636 A |
125 | extern int default_preemption_rate; |
126 | extern int max_unsafe_quanta; | |
127 | extern int max_poll_quanta; | |
91447636 A |
128 | extern unsigned int panic_is_inited; |
129 | ||
0c530ab8 A |
130 | int db_run_mode; |
131 | ||
0c530ab8 A |
132 | volatile int pbtcpu = -1; |
133 | hw_lock_data_t pbtlock; /* backtrace print lock */ | |
134 | uint32_t pbtcnt = 0; | |
135 | ||
0c530ab8 A |
136 | typedef struct _cframe_t { |
137 | struct _cframe_t *prev; | |
138 | unsigned caller; | |
139 | unsigned args[0]; | |
140 | } cframe_t; | |
141 | ||
2d21ac55 A |
142 | static unsigned panic_io_port; |
143 | static unsigned commit_paniclog_to_nvram; | |
0c530ab8 | 144 | |
1c79356b | 145 | void |
2d21ac55 | 146 | machine_startup(void) |
1c79356b | 147 | { |
55e303ae | 148 | int boot_arg; |
1c79356b | 149 | |
55e303ae A |
150 | #if 0 |
151 | if( PE_get_hotkey( kPEControlKey )) | |
152 | halt_in_debugger = halt_in_debugger ? 0 : 1; | |
1c79356b A |
153 | #endif |
154 | ||
55e303ae A |
155 | if (PE_parse_boot_arg("debug", &boot_arg)) { |
156 | if (boot_arg & DB_HALT) halt_in_debugger=1; | |
2d21ac55 | 157 | if (boot_arg & DB_PRT) disable_debug_output=FALSE; |
55e303ae A |
158 | if (boot_arg & DB_SLOG) systemLogDiags=TRUE; |
159 | if (boot_arg & DB_NMI) panicDebugging=TRUE; | |
160 | if (boot_arg & DB_LOG_PI_SCRN) logPanicDataToScreen=TRUE; | |
161 | } | |
1c79356b | 162 | |
2d21ac55 A |
163 | if (!PE_parse_boot_arg("nvram_paniclog", &commit_paniclog_to_nvram)) |
164 | commit_paniclog_to_nvram = 1; | |
165 | ||
166 | /* | |
167 | * Entering the debugger will put the CPUs into a "safe" | |
168 | * power mode. | |
169 | */ | |
170 | if (PE_parse_boot_arg("pmsafe_debug", &boot_arg)) | |
171 | pmsafe_debug = boot_arg; | |
172 | ||
55e303ae A |
173 | #if NOTYET |
174 | hw_lock_init(&debugger_lock); /* initialize debugger lock */ | |
6601e61a | 175 | #endif |
0c530ab8 | 176 | hw_lock_init(&pbtlock); /* initialize print backtrace lock */ |
1c79356b A |
177 | |
178 | #if MACH_KDB | |
1c79356b | 179 | /* |
55e303ae | 180 | * Initialize KDB |
1c79356b | 181 | */ |
55e303ae A |
182 | #if DB_MACHINE_COMMANDS |
183 | db_machine_commands_install(ppc_db_commands); | |
184 | #endif /* DB_MACHINE_COMMANDS */ | |
1c79356b A |
185 | ddb_init(); |
186 | ||
55e303ae A |
187 | if (boot_arg & DB_KDB) |
188 | current_debugger = KDB_CUR_DB; | |
189 | ||
1c79356b A |
190 | /* |
191 | * Cause a breakpoint trap to the debugger before proceeding | |
192 | * any further if the proper option bit was specified in | |
193 | * the boot flags. | |
1c79356b | 194 | */ |
55e303ae A |
195 | if (halt_in_debugger && (current_debugger == KDB_CUR_DB)) { |
196 | Debugger("inline call to debugger(machine_startup)"); | |
197 | halt_in_debugger = 0; | |
198 | active_debugger =1; | |
199 | } | |
200 | #endif /* MACH_KDB */ | |
201 | ||
202 | if (PE_parse_boot_arg("preempt", &boot_arg)) { | |
55e303ae | 203 | default_preemption_rate = boot_arg; |
1c79356b | 204 | } |
55e303ae | 205 | if (PE_parse_boot_arg("unsafe", &boot_arg)) { |
55e303ae A |
206 | max_unsafe_quanta = boot_arg; |
207 | } | |
208 | if (PE_parse_boot_arg("poll", &boot_arg)) { | |
55e303ae A |
209 | max_poll_quanta = boot_arg; |
210 | } | |
211 | if (PE_parse_boot_arg("yield", &boot_arg)) { | |
55e303ae A |
212 | sched_poll_yield_shift = boot_arg; |
213 | } | |
91447636 A |
214 | if (PE_parse_boot_arg("idlehalt", &boot_arg)) { |
215 | idlehalt = boot_arg; | |
216 | } | |
0c530ab8 A |
217 | /* The I/O port to issue a read from, in the event of a panic. Useful for |
218 | * triggering logic analyzers. | |
219 | */ | |
220 | if (PE_parse_boot_arg("panic_io_port", &boot_arg)) { | |
221 | /*I/O ports range from 0 through 0xFFFF */ | |
222 | panic_io_port = boot_arg & 0xffff; | |
223 | } | |
224 | ||
55e303ae A |
225 | machine_conf(); |
226 | ||
227 | #if NOTYET | |
228 | ml_thrm_init(); /* Start thermal monitoring on this processor */ | |
1c79356b A |
229 | #endif |
230 | ||
231 | /* | |
232 | * Start the system. | |
233 | */ | |
91447636 A |
234 | kernel_bootstrap(); |
235 | /*NOTREACHED*/ | |
1c79356b A |
236 | } |
237 | ||
55e303ae A |
238 | |
239 | static void | |
240 | machine_conf(void) | |
1c79356b | 241 | { |
55e303ae | 242 | machine_info.memory_size = mem_size; |
1c79356b A |
243 | } |
244 | ||
0c530ab8 A |
245 | |
246 | extern void *gPEEFIRuntimeServices; | |
247 | extern void *gPEEFISystemTable; | |
248 | ||
249 | /*- | |
250 | * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or | |
251 | * code or tables extracted from it, as desired without restriction. | |
252 | * | |
253 | * First, the polynomial itself and its table of feedback terms. The | |
254 | * polynomial is | |
255 | * X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 | |
256 | * | |
257 | * Note that we take it "backwards" and put the highest-order term in | |
258 | * the lowest-order bit. The X^32 term is "implied"; the LSB is the | |
259 | * X^31 term, etc. The X^0 term (usually shown as "+1") results in | |
260 | * the MSB being 1 | |
261 | * | |
262 | * Note that the usual hardware shift register implementation, which | |
263 | * is what we're using (we're merely optimizing it by doing eight-bit | |
264 | * chunks at a time) shifts bits into the lowest-order term. In our | |
265 | * implementation, that means shifting towards the right. Why do we | |
266 | * do it this way? Because the calculated CRC must be transmitted in | |
267 | * order from highest-order term to lowest-order term. UARTs transmit | |
268 | * characters in order from LSB to MSB. By storing the CRC this way | |
269 | * we hand it to the UART in the order low-byte to high-byte; the UART | |
270 | * sends each low-bit to hight-bit; and the result is transmission bit | |
271 | * by bit from highest- to lowest-order term without requiring any bit | |
272 | * shuffling on our part. Reception works similarly | |
273 | * | |
274 | * The feedback terms table consists of 256, 32-bit entries. Notes | |
275 | * | |
276 | * The table can be generated at runtime if desired; code to do so | |
277 | * is shown later. It might not be obvious, but the feedback | |
278 | * terms simply represent the results of eight shift/xor opera | |
279 | * tions for all combinations of data and CRC register values | |
280 | * | |
281 | * The values must be right-shifted by eight bits by the "updcrc | |
282 | * logic; the shift must be unsigned (bring in zeroes). On some | |
283 | * hardware you could probably optimize the shift in assembler by | |
284 | * using byte-swap instructions | |
285 | * polynomial $edb88320 | |
286 | * | |
287 | * | |
288 | * CRC32 code derived from work by Gary S. Brown. | |
289 | */ | |
290 | ||
291 | static uint32_t crc32_tab[] = { | |
292 | 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, | |
293 | 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, | |
294 | 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, | |
295 | 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, | |
296 | 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, | |
297 | 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, | |
298 | 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, | |
299 | 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, | |
300 | 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, | |
301 | 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, | |
302 | 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, | |
303 | 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, | |
304 | 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, | |
305 | 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, | |
306 | 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, | |
307 | 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, | |
308 | 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, | |
309 | 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, | |
310 | 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, | |
311 | 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, | |
312 | 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, | |
313 | 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, | |
314 | 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, | |
315 | 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, | |
316 | 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, | |
317 | 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, | |
318 | 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, | |
319 | 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, | |
320 | 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, | |
321 | 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, | |
322 | 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, | |
323 | 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, | |
324 | 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, | |
325 | 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, | |
326 | 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, | |
327 | 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, | |
328 | 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, | |
329 | 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, | |
330 | 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, | |
331 | 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, | |
332 | 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, | |
333 | 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, | |
334 | 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d | |
335 | }; | |
336 | ||
337 | static uint32_t | |
338 | crc32(uint32_t crc, const void *buf, size_t size) | |
339 | { | |
340 | const uint8_t *p; | |
341 | ||
342 | p = buf; | |
343 | crc = crc ^ ~0U; | |
344 | ||
345 | while (size--) | |
346 | crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8); | |
347 | ||
348 | return crc ^ ~0U; | |
349 | } | |
350 | ||
351 | static void | |
352 | efi_set_tables_64(EFI_SYSTEM_TABLE_64 * system_table) | |
353 | { | |
354 | EFI_RUNTIME_SERVICES_64 *runtime; | |
355 | uint32_t hdr_cksum; | |
356 | uint32_t cksum; | |
357 | ||
2d21ac55 | 358 | kprintf("Processing 64-bit EFI tables at %p\n", system_table); |
0c530ab8 A |
359 | do { |
360 | if (system_table->Hdr.Signature != EFI_SYSTEM_TABLE_SIGNATURE) { | |
361 | kprintf("Bad EFI system table signature\n"); | |
362 | break; | |
363 | } | |
364 | // Verify signature of the system table | |
365 | hdr_cksum = system_table->Hdr.CRC32; | |
366 | system_table->Hdr.CRC32 = 0; | |
367 | cksum = crc32(0L, system_table, system_table->Hdr.HeaderSize); | |
368 | ||
369 | //kprintf("System table calculated CRC32 = 0x%x, header = 0x%x\n", cksum, hdr_cksum); | |
370 | system_table->Hdr.CRC32 = hdr_cksum; | |
371 | if (cksum != hdr_cksum) { | |
372 | kprintf("Bad EFI system table checksum\n"); | |
373 | break; | |
374 | } | |
375 | ||
376 | gPEEFISystemTable = system_table; | |
377 | ||
378 | kprintf("RuntimeServices table at 0x%qx\n", system_table->RuntimeServices); | |
2d21ac55 A |
379 | runtime = (EFI_RUNTIME_SERVICES_64 *) (uintptr_t)system_table->RuntimeServices; // XXX |
380 | kprintf("Checking runtime services table %p\n", runtime); | |
0c530ab8 A |
381 | if (runtime->Hdr.Signature != EFI_RUNTIME_SERVICES_SIGNATURE) { |
382 | kprintf("Bad EFI runtime table signature\n"); | |
383 | break; | |
384 | } | |
385 | ||
386 | // Verify signature of runtime services table | |
387 | hdr_cksum = runtime->Hdr.CRC32; | |
388 | runtime->Hdr.CRC32 = 0; | |
389 | cksum = crc32(0L, runtime, runtime->Hdr.HeaderSize); | |
390 | ||
391 | //kprintf("Runtime table calculated CRC32 = 0x%x, header = 0x%x\n", cksum, hdr_cksum); | |
392 | runtime->Hdr.CRC32 = hdr_cksum; | |
393 | if (cksum != hdr_cksum) { | |
394 | kprintf("Bad EFI runtime table checksum\n"); | |
395 | break; | |
396 | } | |
397 | ||
398 | gPEEFIRuntimeServices = runtime; | |
399 | } | |
400 | while (FALSE); | |
401 | } | |
402 | ||
403 | static void | |
404 | efi_set_tables_32(EFI_SYSTEM_TABLE * system_table) | |
405 | { | |
406 | EFI_RUNTIME_SERVICES *runtime; | |
407 | uint32_t hdr_cksum; | |
408 | uint32_t cksum; | |
409 | ||
2d21ac55 | 410 | kprintf("Processing 32-bit EFI tables at %p\n", system_table); |
0c530ab8 A |
411 | do { |
412 | if (system_table->Hdr.Signature != EFI_SYSTEM_TABLE_SIGNATURE) { | |
413 | kprintf("Bad EFI system table signature\n"); | |
414 | break; | |
415 | } | |
416 | // Verify signature of the system table | |
417 | hdr_cksum = system_table->Hdr.CRC32; | |
418 | system_table->Hdr.CRC32 = 0; | |
419 | cksum = crc32(0L, system_table, system_table->Hdr.HeaderSize); | |
420 | ||
421 | //kprintf("System table calculated CRC32 = 0x%x, header = 0x%x\n", cksum, hdr_cksum); | |
422 | system_table->Hdr.CRC32 = hdr_cksum; | |
423 | if (cksum != hdr_cksum) { | |
424 | kprintf("Bad EFI system table checksum\n"); | |
425 | break; | |
426 | } | |
427 | ||
428 | gPEEFISystemTable = system_table; | |
429 | ||
2d21ac55 | 430 | kprintf("RuntimeServices table at %p\n", system_table->RuntimeServices); |
0c530ab8 A |
431 | runtime = (EFI_RUNTIME_SERVICES *) system_table->RuntimeServices; |
432 | if (runtime->Hdr.Signature != EFI_RUNTIME_SERVICES_SIGNATURE) { | |
433 | kprintf("Bad EFI runtime table signature\n"); | |
434 | break; | |
435 | } | |
436 | ||
437 | // Verify signature of runtime services table | |
438 | hdr_cksum = runtime->Hdr.CRC32; | |
439 | runtime->Hdr.CRC32 = 0; | |
440 | cksum = crc32(0L, runtime, runtime->Hdr.HeaderSize); | |
441 | ||
442 | //kprintf("Runtime table calculated CRC32 = 0x%x, header = 0x%x\n", cksum, hdr_cksum); | |
443 | runtime->Hdr.CRC32 = hdr_cksum; | |
444 | if (cksum != hdr_cksum) { | |
445 | kprintf("Bad EFI runtime table checksum\n"); | |
446 | break; | |
447 | } | |
448 | ||
449 | gPEEFIRuntimeServices = runtime; | |
450 | } | |
451 | while (FALSE); | |
452 | } | |
453 | ||
454 | ||
455 | /* Map in EFI runtime areas. */ | |
456 | static void | |
457 | efi_init(void) | |
458 | { | |
459 | boot_args *args = (boot_args *)PE_state.bootArgs; | |
460 | ||
461 | kprintf("Initializing EFI runtime services\n"); | |
462 | ||
463 | do | |
464 | { | |
2d21ac55 | 465 | vm_offset_t vm_size, vm_addr; |
0c530ab8 A |
466 | vm_map_offset_t phys_addr; |
467 | EfiMemoryRange *mptr; | |
468 | unsigned int msize, mcount; | |
469 | unsigned int i; | |
470 | ||
471 | msize = args->MemoryMapDescriptorSize; | |
472 | mcount = args->MemoryMapSize / msize; | |
473 | ||
474 | mptr = (EfiMemoryRange *)args->MemoryMap; | |
475 | for (i=0; i < mcount; i++, mptr = (EfiMemoryRange *)(((vm_offset_t)mptr) + msize)) { | |
476 | if (((mptr->Attribute & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME) ) { | |
477 | vm_size = i386_ptob((uint32_t)mptr->NumberOfPages); | |
478 | vm_addr = (vm_offset_t) mptr->VirtualStart; | |
479 | phys_addr = (vm_map_offset_t) mptr->PhysicalStart; | |
480 | pmap_map(vm_addr, phys_addr, phys_addr + round_page(vm_size), | |
481 | (mptr->Type == kEfiRuntimeServicesCode) ? VM_PROT_READ | VM_PROT_EXECUTE : VM_PROT_READ|VM_PROT_WRITE, | |
482 | (mptr->Type == EfiMemoryMappedIO) ? VM_WIMG_IO : VM_WIMG_USE_DEFAULT); | |
483 | } | |
484 | } | |
485 | ||
486 | if (args->Version > 1) | |
487 | panic("Incompatible boot args version %d\n", args->Version); | |
488 | ||
489 | kprintf("Boot args version %d revision %d mode %d\n", args->Version, args->Revision, args->efiMode); | |
490 | if (args->Revision >= 4 && args->efiMode == kBootArgsEfiMode64) { | |
491 | efi_set_tables_64((EFI_SYSTEM_TABLE_64 *) args->efiSystemTable); | |
492 | } else { | |
493 | efi_set_tables_32((EFI_SYSTEM_TABLE *) args->efiSystemTable); | |
494 | } | |
495 | } | |
496 | while (FALSE); | |
497 | ||
498 | return; | |
499 | } | |
500 | ||
501 | /* Remap EFI runtime areas. */ | |
502 | void | |
503 | hibernate_newruntime_map(void * map, vm_size_t map_size, uint32_t system_table_offset) | |
504 | { | |
505 | boot_args *args = (boot_args *)PE_state.bootArgs; | |
506 | ||
507 | kprintf("Reinitializing EFI runtime services\n"); | |
508 | ||
509 | if (args->Revision < 3) | |
510 | return; | |
511 | do | |
512 | { | |
2d21ac55 | 513 | vm_offset_t vm_size, vm_addr; |
0c530ab8 A |
514 | vm_map_offset_t phys_addr; |
515 | EfiMemoryRange *mptr; | |
516 | unsigned int msize, mcount; | |
517 | unsigned int i; | |
518 | ||
519 | gPEEFISystemTable = 0; | |
520 | gPEEFIRuntimeServices = 0; | |
521 | ||
522 | system_table_offset += ptoa_32(args->efiRuntimeServicesPageStart); | |
523 | ||
2d21ac55 A |
524 | kprintf("Old system table 0x%x, new 0x%x\n", |
525 | (uint32_t)args->efiSystemTable, system_table_offset); | |
0c530ab8 | 526 | |
2d21ac55 | 527 | args->efiSystemTable = system_table_offset; |
0c530ab8 A |
528 | |
529 | kprintf("Old map:\n"); | |
530 | msize = args->MemoryMapDescriptorSize; | |
531 | mcount = args->MemoryMapSize / msize; | |
532 | mptr = (EfiMemoryRange *)args->MemoryMap; | |
533 | for (i=0; i < mcount; i++, mptr = (EfiMemoryRange *)(((vm_offset_t)mptr) + msize)) { | |
534 | if ((mptr->Attribute & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME) { | |
535 | ||
536 | vm_size = i386_ptob((uint32_t)mptr->NumberOfPages); | |
537 | vm_addr = (vm_offset_t) mptr->VirtualStart; | |
538 | phys_addr = (vm_map_offset_t) mptr->PhysicalStart; | |
539 | ||
2d21ac55 | 540 | kprintf("mapping[%u] %qx @ %x, %llu\n", mptr->Type, phys_addr, vm_addr, mptr->NumberOfPages); |
0c530ab8 A |
541 | } |
542 | } | |
543 | ||
544 | pmap_remove(kernel_pmap, i386_ptob(args->efiRuntimeServicesPageStart), | |
545 | i386_ptob(args->efiRuntimeServicesPageStart + args->efiRuntimeServicesPageCount)); | |
546 | ||
547 | kprintf("New map:\n"); | |
548 | msize = args->MemoryMapDescriptorSize; | |
549 | mcount = map_size / msize; | |
550 | mptr = map; | |
551 | for (i=0; i < mcount; i++, mptr = (EfiMemoryRange *)(((vm_offset_t)mptr) + msize)) { | |
552 | if ((mptr->Attribute & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME) { | |
553 | ||
554 | vm_size = i386_ptob((uint32_t)mptr->NumberOfPages); | |
555 | vm_addr = (vm_offset_t) mptr->VirtualStart; | |
556 | phys_addr = (vm_map_offset_t) mptr->PhysicalStart; | |
557 | ||
2d21ac55 | 558 | kprintf("mapping[%u] %qx @ %x, %llu\n", mptr->Type, phys_addr, vm_addr, mptr->NumberOfPages); |
0c530ab8 A |
559 | |
560 | pmap_map(vm_addr, phys_addr, phys_addr + round_page(vm_size), | |
561 | (mptr->Type == kEfiRuntimeServicesCode) ? VM_PROT_READ | VM_PROT_EXECUTE : VM_PROT_READ|VM_PROT_WRITE, | |
562 | (mptr->Type == EfiMemoryMappedIO) ? VM_WIMG_IO : VM_WIMG_USE_DEFAULT); | |
563 | } | |
564 | } | |
565 | ||
566 | if (args->Version > 1) | |
567 | panic("Incompatible boot args version %d\n", args->Version); | |
568 | ||
569 | kprintf("Boot args version %d revision %d mode %d\n", args->Version, args->Revision, args->efiMode); | |
570 | if (args->Revision >= 4 && args->efiMode == kBootArgsEfiMode64) { | |
571 | efi_set_tables_64((EFI_SYSTEM_TABLE_64 *) args->efiSystemTable); | |
572 | } else { | |
573 | efi_set_tables_32((EFI_SYSTEM_TABLE *) args->efiSystemTable); | |
574 | } | |
575 | } | |
576 | while (FALSE); | |
577 | ||
578 | kprintf("Done reinitializing EFI runtime services\n"); | |
579 | ||
580 | return; | |
581 | } | |
582 | ||
1c79356b A |
583 | /* |
584 | * Find devices. The system is alive. | |
585 | */ | |
586 | void | |
587 | machine_init(void) | |
588 | { | |
0c530ab8 A |
589 | /* Ensure panic buffer is initialized. */ |
590 | debug_log_init(); | |
591 | ||
1c79356b A |
592 | /* |
593 | * Display CPU identification | |
594 | */ | |
0c530ab8 A |
595 | cpuid_cpu_display("CPU identification"); |
596 | cpuid_feature_display("CPU features"); | |
597 | cpuid_extfeature_display("CPU extended features"); | |
1c79356b | 598 | |
0c530ab8 A |
599 | /* |
600 | * Initialize EFI runtime services. | |
601 | */ | |
602 | efi_init(); | |
55e303ae | 603 | |
55e303ae | 604 | smp_init(); |
1c79356b A |
605 | |
606 | /* | |
607 | * Set up to use floating point. | |
608 | */ | |
609 | init_fpu(); | |
610 | ||
1c79356b A |
611 | /* |
612 | * Configure clock devices. | |
613 | */ | |
614 | clock_config(); | |
91447636 A |
615 | |
616 | /* | |
617 | * Initialize MTRR from boot processor. | |
618 | */ | |
619 | mtrr_init(); | |
620 | ||
621 | /* | |
622 | * Set up PAT for boot processor. | |
623 | */ | |
624 | pat_init(); | |
625 | ||
626 | /* | |
627 | * Free lowmem pages | |
628 | */ | |
629 | x86_lowmem_free(); | |
1c79356b A |
630 | } |
631 | ||
632 | /* | |
633 | * Halt a cpu. | |
634 | */ | |
635 | void | |
636 | halt_cpu(void) | |
637 | { | |
638 | halt_all_cpus(FALSE); | |
639 | } | |
640 | ||
641 | int reset_mem_on_reboot = 1; | |
642 | ||
643 | /* | |
644 | * Halt the system or reboot. | |
645 | */ | |
646 | void | |
9bccf70c | 647 | halt_all_cpus(boolean_t reboot) |
1c79356b | 648 | { |
55e303ae | 649 | if (reboot) { |
55e303ae A |
650 | printf("MACH Reboot\n"); |
651 | PEHaltRestart( kPERestartCPU ); | |
652 | } else { | |
653 | printf("CPU halted\n"); | |
654 | PEHaltRestart( kPEHaltCPU ); | |
1c79356b | 655 | } |
55e303ae | 656 | while(1); |
1c79356b A |
657 | } |
658 | ||
2d21ac55 | 659 | |
0c530ab8 A |
660 | /* Issue an I/O port read if one has been requested - this is an event logic |
661 | * analyzers can use as a trigger point. | |
662 | */ | |
663 | ||
664 | void | |
665 | panic_io_port_read(void) { | |
666 | if (panic_io_port) | |
667 | (void)inb(panic_io_port); | |
668 | } | |
669 | ||
670 | /* For use with the MP rendezvous mechanism | |
671 | */ | |
672 | ||
4a3eedf9 | 673 | #if !CONFIG_EMBEDDED |
0c530ab8 A |
674 | static void |
675 | machine_halt_cpu(__unused void *arg) { | |
676 | panic_io_port_read(); | |
2d21ac55 | 677 | pmCPUHalt(PM_HALT_DEBUG); |
1c79356b | 678 | } |
4a3eedf9 | 679 | #endif |
1c79356b A |
680 | |
681 | void | |
682 | Debugger( | |
683 | const char *message) | |
684 | { | |
0c530ab8 A |
685 | unsigned long pi_size = 0; |
686 | void *stackptr; | |
91447636 | 687 | |
0c530ab8 | 688 | hw_atomic_add(&debug_mode, 1); |
91447636 A |
689 | if (!panic_is_inited) { |
690 | postcode(PANIC_HLT); | |
691 | asm("hlt"); | |
692 | } | |
693 | ||
0c530ab8 | 694 | |
1c79356b | 695 | printf("Debugger called: <%s>\n", message); |
91447636 | 696 | kprintf("Debugger called: <%s>\n", message); |
1c79356b | 697 | |
0c530ab8 A |
698 | /* |
699 | * Skip the graphical panic box if no panic string. | |
700 | * This is the case if we're being called from | |
701 | * host_reboot(,HOST_REBOOT_DEBUGGER) | |
702 | * as a quiet way into the debugger. | |
703 | */ | |
704 | ||
705 | if (panicstr) { | |
706 | disable_preemption(); | |
707 | ||
708 | /* Issue an I/O port read if one has been requested - this is an event logic | |
709 | * analyzers can use as a trigger point. | |
710 | */ | |
711 | panic_io_port_read(); | |
712 | ||
713 | /* Obtain current frame pointer */ | |
714 | __asm__ volatile("movl %%ebp, %0" : "=m" (stackptr)); | |
715 | ||
716 | /* Print backtrace - callee is internally synchronized */ | |
935ed37a | 717 | panic_i386_backtrace(stackptr, 16, NULL, FALSE, NULL); |
0c530ab8 A |
718 | |
719 | /* everything should be printed now so copy to NVRAM | |
720 | */ | |
721 | ||
722 | if( debug_buf_size > 0) { | |
2d21ac55 A |
723 | /* Optionally sync the panic log, if any, to NVRAM |
724 | * This is the default. | |
725 | */ | |
726 | if (commit_paniclog_to_nvram) { | |
0c530ab8 | 727 | unsigned int bufpos; |
935ed37a | 728 | uintptr_t cr0; |
2d21ac55 | 729 | |
0c530ab8 A |
730 | debug_putc(0); |
731 | ||
732 | /* Now call the compressor */ | |
733 | /* XXX Consider using the WKdm compressor in the | |
734 | * future, rather than just packing - would need to | |
735 | * be co-ordinated with crashreporter, which decodes | |
2d21ac55 A |
736 | * this post-restart. The compressor should be |
737 | * capable of in-place compression. | |
0c530ab8 | 738 | */ |
2d21ac55 A |
739 | bufpos = packA(debug_buf, |
740 | (unsigned int) (debug_buf_ptr - debug_buf), debug_buf_size); | |
0c530ab8 A |
741 | /* If compression was successful, |
742 | * use the compressed length | |
743 | */ | |
2d21ac55 A |
744 | pi_size = bufpos ? bufpos : (unsigned) (debug_buf_ptr - debug_buf); |
745 | ||
0c530ab8 A |
746 | /* Save panic log to non-volatile store |
747 | * Panic info handler must truncate data that is | |
748 | * too long for this platform. | |
749 | * This call must save data synchronously, | |
750 | * since we can subsequently halt the system. | |
751 | */ | |
2d21ac55 | 752 | kprintf("Attempting to commit panic log to NVRAM\n"); |
935ed37a A |
753 | /* The following sequence is a workaround for: |
754 | * <rdar://problem/5915669> SnowLeopard10A67: AppleEFINVRAM should not invoke | |
755 | * any routines that use floating point (MMX in this case) when saving panic | |
756 | * logs to nvram/flash. | |
757 | */ | |
758 | cr0 = get_cr0(); | |
759 | clear_ts(); | |
760 | ||
0c530ab8 A |
761 | pi_size = PESavePanicInfo((unsigned char *)debug_buf, |
762 | pi_size ); | |
935ed37a | 763 | set_cr0(cr0); |
2d21ac55 A |
764 | |
765 | /* Uncompress in-place, to permit examination of | |
766 | * the panic log by debuggers. | |
767 | */ | |
768 | ||
769 | if (bufpos) { | |
770 | unpackA(debug_buf, bufpos); | |
771 | } | |
0c530ab8 A |
772 | } |
773 | } | |
774 | draw_panic_dialog(); | |
775 | ||
776 | if (!panicDebugging) { | |
777 | /* Clear the MP rendezvous function lock, in the event | |
778 | * that a panic occurred while in that codepath. | |
779 | */ | |
780 | mp_rendezvous_break_lock(); | |
2d21ac55 A |
781 | #if CONFIG_EMBEDDED |
782 | PEHaltRestart(kPEPanicRestartCPU); | |
783 | #else | |
0c530ab8 A |
784 | /* Force all CPUs to disable interrupts and HLT. |
785 | * We've panicked, and shouldn't depend on the | |
786 | * PEHaltRestart() mechanism, which relies on several | |
787 | * bits of infrastructure. | |
788 | */ | |
789 | mp_rendezvous_no_intrs(machine_halt_cpu, NULL); | |
2d21ac55 | 790 | #endif |
0c530ab8 A |
791 | /* NOT REACHED */ |
792 | } | |
793 | } | |
55e303ae | 794 | |
1c79356b | 795 | __asm__("int3"); |
0c530ab8 | 796 | hw_atomic_sub(&debug_mode, 1); |
1c79356b A |
797 | } |
798 | ||
799 | void | |
91447636 | 800 | enable_bluebox(void) |
1c79356b | 801 | { |
1c79356b | 802 | } |
0c530ab8 | 803 | |
91447636 A |
804 | void |
805 | disable_bluebox(void) | |
1c79356b A |
806 | { |
807 | } | |
808 | ||
809 | char * | |
91447636 | 810 | machine_boot_info(char *buf, __unused vm_size_t size) |
1c79356b A |
811 | { |
812 | *buf ='\0'; | |
813 | return buf; | |
814 | } | |
815 | ||
0c530ab8 A |
816 | |
817 | struct pasc { | |
818 | unsigned a: 7; | |
819 | unsigned b: 7; | |
820 | unsigned c: 7; | |
821 | unsigned d: 7; | |
822 | unsigned e: 7; | |
823 | unsigned f: 7; | |
824 | unsigned g: 7; | |
825 | unsigned h: 7; | |
826 | } __attribute__((packed)); | |
827 | ||
828 | typedef struct pasc pasc_t; | |
829 | ||
0c530ab8 A |
830 | /* Routines for address - symbol translation. Not called unless the "keepsyms" |
831 | * boot-arg is supplied. | |
832 | */ | |
833 | ||
834 | static int | |
835 | panic_print_macho_symbol_name(struct mach_header *mh, vm_address_t search) | |
836 | { | |
837 | struct nlist *sym = NULL; | |
838 | struct load_command *cmd; | |
839 | struct segment_command *orig_ts = NULL, *orig_le = NULL; | |
840 | struct symtab_command *orig_st = NULL; | |
841 | unsigned int i; | |
842 | char *strings, *bestsym = NULL; | |
843 | vm_address_t bestaddr = 0, diff, curdiff; | |
844 | ||
845 | if (mh->magic != MH_MAGIC) { | |
846 | /* bad magic number */ | |
847 | return 0; | |
848 | } | |
849 | ||
850 | cmd = (struct load_command *) &mh[1]; | |
851 | for (i = 0; i < mh->ncmds; i++) { | |
852 | if (cmd->cmd == LC_SEGMENT) { | |
853 | struct segment_command *orig_sg = (struct segment_command *) cmd; | |
854 | ||
2d21ac55 A |
855 | if (strncmp(SEG_TEXT, orig_sg->segname, |
856 | sizeof(orig_sg->segname)) == 0) | |
0c530ab8 | 857 | orig_ts = orig_sg; |
2d21ac55 A |
858 | else if (strncmp(SEG_LINKEDIT, orig_sg->segname, |
859 | sizeof(orig_sg->segname)) == 0) | |
0c530ab8 | 860 | orig_le = orig_sg; |
2d21ac55 A |
861 | else if (strncmp("", orig_sg->segname, |
862 | sizeof(orig_sg->segname)) == 0) | |
0c530ab8 A |
863 | orig_ts = orig_sg; /* kexts have a single unnamed segment */ |
864 | } | |
865 | else if (cmd->cmd == LC_SYMTAB) | |
866 | orig_st = (struct symtab_command *) cmd; | |
867 | ||
868 | cmd = (struct load_command *) ((caddr_t) cmd + cmd->cmdsize); | |
869 | } | |
870 | ||
871 | if ((orig_ts == NULL) || (orig_st == NULL) || (orig_le == NULL)) | |
872 | return 0; | |
873 | ||
874 | /* kexts don't have a LINKEDIT segment for now, so we'll never get this far for kexts */ | |
875 | ||
876 | vm_address_t slide = ((vm_address_t)mh) - orig_ts->vmaddr; | |
877 | if (slide != 0) | |
878 | search -= slide; /* adjusting search since the binary has slid */ | |
879 | ||
880 | if ((search < orig_ts->vmaddr) || | |
881 | (search >= orig_ts->vmaddr + orig_ts->vmsize)) { | |
882 | /* search out of range for this mach header */ | |
883 | return 0; | |
884 | } | |
885 | ||
886 | sym = (struct nlist *)orig_le->vmaddr; | |
887 | strings = ((char *)sym) + orig_st->nsyms * sizeof(struct nlist); | |
888 | diff = search; | |
889 | ||
890 | for (i = 0; i < orig_st->nsyms; i++) { | |
891 | if (sym[i].n_value <= search) { | |
892 | curdiff = search - (vm_address_t)sym[i].n_value; | |
893 | if (curdiff < diff) { | |
894 | diff = curdiff; | |
895 | bestaddr = sym[i].n_value; | |
896 | bestsym = strings + sym[i].n_un.n_strx; | |
897 | } | |
898 | } | |
899 | } | |
900 | ||
901 | if (bestsym != NULL) { | |
902 | if (diff != 0) { | |
2d21ac55 | 903 | kdb_printf("%s + 0x%08x \n", bestsym, diff); |
0c530ab8 | 904 | } else { |
2d21ac55 | 905 | kdb_printf("%s \n", bestsym); |
0c530ab8 A |
906 | } |
907 | return 1; | |
908 | } | |
909 | return 0; | |
910 | } | |
911 | ||
912 | extern kmod_info_t * kmod; /* the list of modules */ | |
913 | ||
914 | static void | |
915 | panic_print_kmod_symbol_name(vm_address_t search) | |
916 | { | |
917 | kmod_info_t * current_kmod = kmod; | |
918 | ||
919 | while (current_kmod != NULL) { | |
920 | if ((current_kmod->address <= search) && | |
921 | (current_kmod->address + current_kmod->size > search)) | |
922 | break; | |
923 | current_kmod = current_kmod->next; | |
924 | } | |
925 | if (current_kmod != NULL) { | |
926 | /* if kexts had symbol table loaded, we'd call search_symbol_name again; alas, they don't */ | |
2d21ac55 | 927 | kdb_printf("%s + %d \n", current_kmod->name, search - current_kmod->address); |
0c530ab8 A |
928 | } |
929 | } | |
930 | ||
931 | extern struct mach_header _mh_execute_header; /* the kernel's mach header */ | |
932 | ||
933 | static void | |
934 | panic_print_symbol_name(vm_address_t search) | |
935 | { | |
936 | /* try searching in the kernel */ | |
937 | if (panic_print_macho_symbol_name(&_mh_execute_header, search) == 0) { | |
938 | /* that failed, now try to search for the right kext */ | |
939 | panic_print_kmod_symbol_name(search); | |
940 | } | |
941 | } | |
942 | ||
943 | /* Generate a backtrace, given a frame pointer - this routine | |
944 | * should walk the stack safely. The trace is appended to the panic log | |
945 | * and conditionally, to the console. If the trace contains kernel module | |
946 | * addresses, display the module name, load address and dependencies. | |
947 | */ | |
948 | ||
949 | #define DUMPFRAMES 32 | |
950 | #define PBT_TIMEOUT_CYCLES (5 * 1000 * 1000 * 1000ULL) | |
951 | void | |
935ed37a | 952 | panic_i386_backtrace(void *_frame, int nframes, const char *msg, boolean_t regdump, x86_saved_state_t *regs) |
0c530ab8 A |
953 | { |
954 | cframe_t *frame = (cframe_t *)_frame; | |
955 | vm_offset_t raddrs[DUMPFRAMES]; | |
935ed37a | 956 | vm_offset_t PC = 0; |
0c530ab8 A |
957 | int frame_index; |
958 | volatile uint32_t *ppbtcnt = &pbtcnt; | |
959 | uint64_t bt_tsc_timeout; | |
960 | boolean_t keepsyms = FALSE; | |
961 | ||
962 | if(pbtcpu != cpu_number()) { | |
963 | hw_atomic_add(&pbtcnt, 1); | |
964 | /* Spin on print backtrace lock, which serializes output | |
965 | * Continue anyway if a timeout occurs. | |
966 | */ | |
2d21ac55 | 967 | hw_lock_to(&pbtlock, LockTimeOutTSC); |
0c530ab8 A |
968 | pbtcpu = cpu_number(); |
969 | } | |
970 | ||
971 | PE_parse_boot_arg("keepsyms", &keepsyms); | |
972 | ||
935ed37a A |
973 | if (msg != NULL) { |
974 | kdb_printf(msg); | |
975 | } | |
976 | ||
977 | if ((regdump == TRUE) && (regs != NULL)) { | |
978 | x86_saved_state32_t *ss32p = saved_state32(regs); | |
979 | ||
980 | kdb_printf( | |
981 | "EAX: 0x%08x, EBX: 0x%08x, ECX: 0x%08x, EDX: 0x%08x\n" | |
982 | "CR2: 0x%08x, EBP: 0x%08x, ESI: 0x%08x, EDI: 0x%08x\n" | |
983 | "EFL: 0x%08x, EIP: 0x%08x, CS: 0x%08x, DS: 0x%08x\n", | |
984 | ss32p->eax,ss32p->ebx,ss32p->ecx,ss32p->edx, | |
985 | ss32p->cr2,ss32p->ebp,ss32p->esi,ss32p->edi, | |
986 | ss32p->efl,ss32p->eip,ss32p->cs, ss32p->ds); | |
987 | PC = ss32p->eip; | |
988 | } | |
989 | ||
990 | kdb_printf("Backtrace (CPU %d), " | |
991 | "Frame : Return Address (4 potential args on stack)\n", cpu_number()); | |
0c530ab8 A |
992 | |
993 | for (frame_index = 0; frame_index < nframes; frame_index++) { | |
994 | vm_offset_t curframep = (vm_offset_t) frame; | |
995 | ||
996 | if (!curframep) | |
997 | break; | |
998 | ||
999 | if (curframep & 0x3) { | |
1000 | kdb_printf("Unaligned frame\n"); | |
1001 | goto invalid; | |
1002 | } | |
1003 | ||
1004 | if (!kvtophys(curframep) || | |
1005 | !kvtophys(curframep + sizeof(cframe_t))) { | |
1006 | kdb_printf("No mapping exists for frame pointer\n"); | |
1007 | goto invalid; | |
1008 | } | |
1009 | ||
2d21ac55 | 1010 | kdb_printf("%p : 0x%x ", frame, frame->caller); |
0c530ab8 A |
1011 | if (frame_index < DUMPFRAMES) |
1012 | raddrs[frame_index] = frame->caller; | |
1013 | ||
1014 | if (kvtophys((vm_offset_t)&(frame->args[3]))) | |
2d21ac55 | 1015 | kdb_printf("(0x%x 0x%x 0x%x 0x%x) \n", |
0c530ab8 A |
1016 | frame->args[0], frame->args[1], |
1017 | frame->args[2], frame->args[3]); | |
1018 | ||
1019 | /* Display address-symbol translation only if the "keepsyms" | |
1020 | * boot-arg is suppplied, since we unload LINKEDIT otherwise. | |
1021 | * This routine is potentially unsafe; also, function | |
1022 | * boundary identification is unreliable after a strip -x. | |
1023 | */ | |
1024 | if (keepsyms) | |
1025 | panic_print_symbol_name((vm_address_t)frame->caller); | |
1026 | ||
1027 | /* Stack grows downward */ | |
1028 | if (frame->prev < frame) { | |
1029 | frame = frame->prev; | |
1030 | goto invalid; | |
1031 | } | |
1032 | frame = frame->prev; | |
1033 | } | |
1034 | ||
1035 | if (frame_index >= nframes) | |
1036 | kdb_printf("\tBacktrace continues...\n"); | |
1037 | ||
1038 | goto out; | |
1039 | ||
1040 | invalid: | |
2d21ac55 | 1041 | kdb_printf("Backtrace terminated-invalid frame pointer %p\n",frame); |
0c530ab8 A |
1042 | out: |
1043 | ||
1044 | /* Identify kernel modules in the backtrace and display their | |
1045 | * load addresses and dependencies. This routine should walk | |
1046 | * the kmod list safely. | |
1047 | */ | |
1048 | if (frame_index) | |
1049 | kmod_dump((vm_offset_t *)&raddrs[0], frame_index); | |
1050 | ||
935ed37a A |
1051 | if (PC != 0) |
1052 | kmod_dump(&PC, 1); | |
1053 | ||
2d21ac55 | 1054 | panic_display_system_configuration(); |
0c530ab8 A |
1055 | /* Release print backtrace lock, to permit other callers in the |
1056 | * event of panics on multiple processors. | |
1057 | */ | |
1058 | hw_lock_unlock(&pbtlock); | |
1059 | hw_atomic_sub(&pbtcnt, 1); | |
1060 | /* Wait for other processors to complete output | |
1061 | * Timeout and continue after PBT_TIMEOUT_CYCLES. | |
1062 | */ | |
1063 | bt_tsc_timeout = rdtsc64() + PBT_TIMEOUT_CYCLES; | |
1064 | while(*ppbtcnt && (rdtsc64() < bt_tsc_timeout)); | |
1065 | } |