xref: /xnu-10002.61.3/pexpert/arm/pe_identify_machine.c (revision 0f4c859e951fba394238ab619495c4e1d54d0f34)
1 /*
2  * Copyright (c) 2007-2021 Apple Inc. All rights reserved.
3  * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
4  */
5 #include <pexpert/pexpert.h>
6 #include <pexpert/boot.h>
7 #include <pexpert/protos.h>
8 #include <pexpert/device_tree.h>
9 
10 #include <pexpert/arm64/board_config.h>
11 
12 #include <kern/clock.h>
13 #include <kern/locks.h>
14 #include <machine/machine_routines.h>
15 #if DEVELOPMENT || DEBUG
16 #include <kern/simple_lock.h>
17 #include <kern/cpu_number.h>
18 #include <os/hash.h>
19 #ifndef MIN
20 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
21 #endif /* MIN */
22 #endif /* DEVELOPMENT || DEBUG */
23 
24 #define PANIC_TRACE_LOG 1
25 #define panic_trace_error(msg, args...) { if (panic_trace_debug == 1) kprintf("panic_trace: " msg "\n", ##args); else if (panic_trace_debug == 2) printf("panic_trace: " msg "\n", ##args); }
26 #if PANIC_TRACE_LOG
27 #define panic_trace_log(msg, args...) { if (panic_trace_debug) panic_trace_error(msg, ##args); }
28 #else
29 #define panic_trace_log(msg, args...)
30 #endif /* PANIC_TRACE_LOG */
31 
32 
33 /* Disable logs by default. */
34 #ifndef CT_DFT_LOGS_ON
35 #define CT_DFT_LOGS_ON 0
36 #endif /* CT_DFT_LOGS_ON */
37 
38 /* Local declarations */
39 void pe_identify_machine(boot_args * bootArgs);
40 
41 /* External declarations */
42 extern void clean_mmu_dcache(void);
43 extern void flush_dcache64(addr64_t addr, unsigned count, int phys);
44 
45 static char    *gPESoCDeviceType;
46 static char     gPESoCDeviceTypeBuffer[SOC_DEVICE_TYPE_BUFFER_SIZE];
47 static vm_offset_t gPESoCBasePhys;
48 
49 static uint32_t pe_arm_init_timer(void *args);
50 
51 #if DEVELOPMENT || DEBUG
52 decl_simple_lock_data(, panic_hook_lock);
53 #endif
54 
55 static boolean_t debug_and_trace_initialized = false;
56 
57 boolean_t
PE_arm_debug_and_trace_initialized(void)58 PE_arm_debug_and_trace_initialized(void)
59 {
60 	return debug_and_trace_initialized;
61 }
62 
63 /*
64  * pe_identify_machine:
65  *
66  * Sets up platform parameters. Returns:    nothing
67  */
68 void
pe_identify_machine(boot_args * bootArgs)69 pe_identify_machine(boot_args * bootArgs)
70 {
71 	OpaqueDTEntryIterator iter;
72 	DTEntry         cpus, cpu;
73 	void const     *value;
74 	unsigned int    size;
75 	int             err;
76 
77 	(void)bootArgs;
78 
79 	if (pe_arm_get_soc_base_phys() == 0) {
80 		return;
81 	}
82 
83 	/* Clear the gPEClockFrequencyInfo struct */
84 	bzero((void *)&gPEClockFrequencyInfo, sizeof(clock_frequency_info_t));
85 
86 	/* Start with default values. */
87 	gPEClockFrequencyInfo.timebase_frequency_hz = 24000000;
88 	gPEClockFrequencyInfo.bus_clock_rate_hz = 100000000;
89 	gPEClockFrequencyInfo.cpu_clock_rate_hz = 400000000;
90 
91 	err = SecureDTLookupEntry(NULL, "/cpus", &cpus);
92 	assert(err == kSuccess);
93 
94 	err = SecureDTInitEntryIterator(cpus, &iter);
95 	assert(err == kSuccess);
96 
97 	while (kSuccess == SecureDTIterateEntries(&iter, &cpu)) {
98 		if ((kSuccess != SecureDTGetProperty(cpu, "state", &value, &size)) ||
99 		    (strncmp((char const *)value, "running", size) != 0)) {
100 			continue;
101 		}
102 
103 		/* Find the time base frequency first. */
104 		if (SecureDTGetProperty(cpu, "timebase-frequency", &value, &size) == kSuccess) {
105 			/*
106 			 * timebase_frequency_hz is only 32 bits, and
107 			 * the device tree should never provide 64
108 			 * bits so this if should never be taken.
109 			 */
110 			if (size == 8) {
111 				gPEClockFrequencyInfo.timebase_frequency_hz = *(uint64_t const *)value;
112 			} else {
113 				gPEClockFrequencyInfo.timebase_frequency_hz = *(uint32_t const *)value;
114 			}
115 		}
116 		gPEClockFrequencyInfo.dec_clock_rate_hz = gPEClockFrequencyInfo.timebase_frequency_hz;
117 
118 		/* Find the bus frequency next. */
119 		if (SecureDTGetProperty(cpu, "bus-frequency", &value, &size) == kSuccess) {
120 			if (size == 8) {
121 				gPEClockFrequencyInfo.bus_frequency_hz = *(uint64_t const *)value;
122 			} else {
123 				gPEClockFrequencyInfo.bus_frequency_hz = *(uint32_t const *)value;
124 			}
125 		}
126 		gPEClockFrequencyInfo.bus_frequency_min_hz = gPEClockFrequencyInfo.bus_frequency_hz;
127 		gPEClockFrequencyInfo.bus_frequency_max_hz = gPEClockFrequencyInfo.bus_frequency_hz;
128 
129 		if (gPEClockFrequencyInfo.bus_frequency_hz < 0x100000000ULL) {
130 			gPEClockFrequencyInfo.bus_clock_rate_hz = gPEClockFrequencyInfo.bus_frequency_hz;
131 		} else {
132 			gPEClockFrequencyInfo.bus_clock_rate_hz = 0xFFFFFFFF;
133 		}
134 
135 		/* Find the memory frequency next. */
136 		if (SecureDTGetProperty(cpu, "memory-frequency", &value, &size) == kSuccess) {
137 			if (size == 8) {
138 				gPEClockFrequencyInfo.mem_frequency_hz = *(uint64_t const *)value;
139 			} else {
140 				gPEClockFrequencyInfo.mem_frequency_hz = *(uint32_t const *)value;
141 			}
142 		}
143 		gPEClockFrequencyInfo.mem_frequency_min_hz = gPEClockFrequencyInfo.mem_frequency_hz;
144 		gPEClockFrequencyInfo.mem_frequency_max_hz = gPEClockFrequencyInfo.mem_frequency_hz;
145 
146 		/* Find the peripheral frequency next. */
147 		if (SecureDTGetProperty(cpu, "peripheral-frequency", &value, &size) == kSuccess) {
148 			if (size == 8) {
149 				gPEClockFrequencyInfo.prf_frequency_hz = *(uint64_t const *)value;
150 			} else {
151 				gPEClockFrequencyInfo.prf_frequency_hz = *(uint32_t const *)value;
152 			}
153 		}
154 		gPEClockFrequencyInfo.prf_frequency_min_hz = gPEClockFrequencyInfo.prf_frequency_hz;
155 		gPEClockFrequencyInfo.prf_frequency_max_hz = gPEClockFrequencyInfo.prf_frequency_hz;
156 
157 		/* Find the fixed frequency next. */
158 		if (SecureDTGetProperty(cpu, "fixed-frequency", &value, &size) == kSuccess) {
159 			if (size == 8) {
160 				gPEClockFrequencyInfo.fix_frequency_hz = *(uint64_t const *)value;
161 			} else {
162 				gPEClockFrequencyInfo.fix_frequency_hz = *(uint32_t const *)value;
163 			}
164 		}
165 		/* Find the cpu frequency last. */
166 		if (SecureDTGetProperty(cpu, "clock-frequency", &value, &size) == kSuccess) {
167 			if (size == 8) {
168 				gPEClockFrequencyInfo.cpu_frequency_hz = *(uint64_t const *)value;
169 			} else {
170 				gPEClockFrequencyInfo.cpu_frequency_hz = *(uint32_t const *)value;
171 			}
172 		}
173 		gPEClockFrequencyInfo.cpu_frequency_min_hz = gPEClockFrequencyInfo.cpu_frequency_hz;
174 		gPEClockFrequencyInfo.cpu_frequency_max_hz = gPEClockFrequencyInfo.cpu_frequency_hz;
175 
176 		if (gPEClockFrequencyInfo.cpu_frequency_hz < 0x100000000ULL) {
177 			gPEClockFrequencyInfo.cpu_clock_rate_hz = gPEClockFrequencyInfo.cpu_frequency_hz;
178 		} else {
179 			gPEClockFrequencyInfo.cpu_clock_rate_hz = 0xFFFFFFFF;
180 		}
181 	}
182 
183 	/* Set the num / den pairs form the hz values. */
184 	gPEClockFrequencyInfo.bus_clock_rate_num = gPEClockFrequencyInfo.bus_clock_rate_hz;
185 	gPEClockFrequencyInfo.bus_clock_rate_den = 1;
186 
187 	gPEClockFrequencyInfo.bus_to_cpu_rate_num =
188 	    (2 * gPEClockFrequencyInfo.cpu_clock_rate_hz) / gPEClockFrequencyInfo.bus_clock_rate_hz;
189 	gPEClockFrequencyInfo.bus_to_cpu_rate_den = 2;
190 
191 	gPEClockFrequencyInfo.bus_to_dec_rate_num = 1;
192 	gPEClockFrequencyInfo.bus_to_dec_rate_den =
193 	    gPEClockFrequencyInfo.bus_clock_rate_hz / gPEClockFrequencyInfo.dec_clock_rate_hz;
194 }
195 
196 vm_offset_t
pe_arm_get_soc_base_phys(void)197 pe_arm_get_soc_base_phys(void)
198 {
199 	DTEntry         entryP;
200 	uintptr_t const *ranges_prop;
201 	uint32_t        prop_size;
202 	char const      *tmpStr;
203 
204 	if (SecureDTFindEntry("name", "arm-io", &entryP) == kSuccess) {
205 		if (gPESoCDeviceType == 0) {
206 			SecureDTGetProperty(entryP, "device_type", (void const **)&tmpStr, &prop_size);
207 			strlcpy(gPESoCDeviceTypeBuffer, tmpStr, SOC_DEVICE_TYPE_BUFFER_SIZE);
208 			gPESoCDeviceType = gPESoCDeviceTypeBuffer;
209 
210 			SecureDTGetProperty(entryP, "ranges", (void const **)&ranges_prop, &prop_size);
211 			gPESoCBasePhys = *(ranges_prop + 1);
212 		}
213 		return gPESoCBasePhys;
214 	}
215 	return 0;
216 }
217 
218 extern void     fleh_fiq_generic(void);
219 
220 vm_offset_t     gPicBase;
221 vm_offset_t     gTimerBase;
222 vm_offset_t     gSocPhys;
223 
224 #if DEVELOPMENT || DEBUG
225 // This block contains the panic trace implementation
226 
227 #define DEFAULT_PANIC_TRACE_MODE panic_trace_disabled
228 
229 TUNABLE_DT_WRITEABLE(panic_trace_t, panic_trace, "/arm-io/cpu-debug-interface",
230     "panic-trace-mode", "panic_trace", DEFAULT_PANIC_TRACE_MODE, TUNABLE_DT_NONE);
231 LCK_GRP_DECLARE(panic_trace_grp, "Panic Trace");
232 LCK_TICKET_DECLARE(panic_trace_lock, &panic_trace_grp);
233 TUNABLE_WRITEABLE(boolean_t, panic_trace_debug, "panic_trace_debug", CT_DFT_LOGS_ON);
234 TUNABLE_WRITEABLE(uint64_t, panic_trace_core_cfg, "panic_trace_core_cfg", 0);
235 TUNABLE_WRITEABLE(uint64_t, panic_trace_ctl, "panic_trace_ctl", 0);
236 TUNABLE_WRITEABLE(uint64_t, panic_trace_pwr_state_ignore, "panic_trace_pwr_state_ignore", 0);
237 TUNABLE(unsigned int, bootarg_stop_clocks, "stop_clocks", 0);
238 extern unsigned int wfi;
239 
240 // The command buffer contains the converted commands from the device tree for commanding cpu_halt, enable_trace, etc.
241 #define DEBUG_COMMAND_BUFFER_SIZE 256
242 typedef struct command_buffer_element {
243 	uintptr_t address;
244 	uintptr_t address_pa;
245 	uintptr_t value;
246 	union cpu_selector {
247 		uint16_t mask;
248 		struct cpu_range {
249 			uint8_t min_cpu;
250 			uint8_t max_cpu;
251 		} range;
252 	} destination_cpu_selector;
253 	uint16_t delay_us;
254 	bool cpu_selector_is_range;
255 	bool is_32bit;
256 } command_buffer_element_t;
257 
258 #define CPU_SELECTOR_SHIFT              (16)
259 #define CPU_SELECTOR_MASK               (0xFFFF << CPU_SELECTOR_SHIFT)
260 #define REGISTER_OFFSET_MASK            ((1 << CPU_SELECTOR_SHIFT) - 1)
261 #define REGISTER_OFFSET(register_prop)  (register_prop & REGISTER_OFFSET_MASK)
262 #define CPU_SELECTOR(register_offset)   ((register_offset & CPU_SELECTOR_MASK) >> CPU_SELECTOR_SHIFT) // Upper 16bits holds the cpu selector
263 #define MAX_WINDOW_SIZE                 0xFFFF
264 #define DELAY_SHIFT                     (32)
265 #define DELAY_MASK                      (0xFFFFULL << DELAY_SHIFT)
266 #define DELAY_US(register_offset)       ((register_offset & DELAY_MASK) >> DELAY_SHIFT)
267 #define CPU_SELECTOR_ISRANGE_MASK       (1ULL << 62)
268 #define REGISTER_32BIT_MASK             (1ULL << 63)
269 #define ALL_CPUS                        0x0000
270 #define RESET_VIRTUAL_ADDRESS_WINDOW    0xFFFFFFFF
271 
272 #define REGISTER_IS_32BIT(register_offset)      ((register_offset & REGISTER_32BIT_MASK) != 0)
273 #define REGISTER_SIZE(register_offset)          (REGISTER_IS_32BIT(register_offset) ? sizeof(uint32_t) : sizeof(uintptr_t))
274 #define CPU_SELECTOR_IS_RANGE(register_offset)  ((register_offset & CPU_SELECTOR_ISRANGE_MASK) != 0)
275 #define CPU_SELECTOR_MIN_CPU(register_offset)   ((CPU_SELECTOR(register_offset) & 0xff00) >> 8)
276 #define CPU_SELECTOR_MAX_CPU(register_offset)   (CPU_SELECTOR(register_offset) & 0x00ff)
277 
278 // Record which CPU is currently running one of our debug commands, so we can trap panic reentrancy to PE_arm_debug_panic_hook.
279 static int running_debug_command_on_cpu_number = -1;
280 
281 // Determine whether the current debug command is intended for this CPU.
282 static inline bool
is_running_cpu_selected(command_buffer_element_t * command)283 is_running_cpu_selected(command_buffer_element_t *command)
284 {
285 	assert(running_debug_command_on_cpu_number >= 0);
286 	if (command->cpu_selector_is_range) {
287 		return running_debug_command_on_cpu_number >= command->destination_cpu_selector.range.min_cpu
288 		       && running_debug_command_on_cpu_number <= command->destination_cpu_selector.range.max_cpu;
289 	} else if (command->destination_cpu_selector.mask == ALL_CPUS) {
290 		return true;
291 	} else {
292 		return !!(command->destination_cpu_selector.mask & (1 << running_debug_command_on_cpu_number));
293 	}
294 }
295 
296 
297 // Pointers into debug_command_buffer for each operation. Assumes runtime will init them to zero.
298 static command_buffer_element_t *cpu_halt;
299 static command_buffer_element_t *enable_trace;
300 static command_buffer_element_t *enable_alt_trace;
301 static command_buffer_element_t *trace_halt;
302 static command_buffer_element_t *enable_stop_clocks;
303 static command_buffer_element_t *stop_clocks;
304 
305 
306 
307 /**************
308 * Public API *
309 **************/
310 
311 static void
pe_init_debug_command(DTEntry entryP,command_buffer_element_t ** command_buffer,const char * entry_name)312 pe_init_debug_command(DTEntry entryP, command_buffer_element_t **command_buffer, const char* entry_name)
313 {
314 	// statically allocate to prevent needing alloc at runtime
315 	static command_buffer_element_t debug_command_buffer[DEBUG_COMMAND_BUFFER_SIZE];
316 	static command_buffer_element_t *next_command_buffer_entry = debug_command_buffer;
317 
318 	// record this pointer but don't assign it to *command_buffer yet, in case we panic while half-initialized
319 	command_buffer_element_t *command_starting_index = next_command_buffer_entry;
320 
321 	uintptr_t const *reg_prop;
322 	uint32_t        prop_size, reg_window_size = 0;
323 	uintptr_t       base_address_pa = 0, debug_reg_window = 0;
324 
325 	if (command_buffer == 0) {
326 		panic_trace_log("%s: %s: no hook to assign this command to\n", __func__, entry_name);
327 		return;
328 	}
329 
330 	if (SecureDTGetProperty(entryP, entry_name, (void const **)&reg_prop, &prop_size) != kSuccess) {
331 		panic("%s: %s: failed to read property from device tree", __func__, entry_name);
332 	}
333 
334 	if (prop_size % (2 * sizeof(*reg_prop))) {
335 		panic("%s: %s: property size %u bytes is not a multiple of %lu",
336 		    __func__, entry_name, prop_size, 2 * sizeof(*reg_prop));
337 	}
338 
339 	// convert to real virt addresses and stuff commands into debug_command_buffer
340 	for (; prop_size; reg_prop += 2, prop_size -= 2 * sizeof(*reg_prop)) {
341 		if (*reg_prop == RESET_VIRTUAL_ADDRESS_WINDOW) {
342 			debug_reg_window = 0; // Create a new window
343 		} else if (debug_reg_window == 0) {
344 			// create a window from virtual address to the specified physical address
345 			base_address_pa = gSocPhys + *reg_prop;
346 			reg_window_size = ((uint32_t)*(reg_prop + 1));
347 			if (reg_window_size > MAX_WINDOW_SIZE) {
348 				panic("%s: %s: %#x-byte window at #%lx exceeds maximum size of %#x",
349 				    __func__, entry_name, reg_window_size, base_address_pa, MAX_WINDOW_SIZE );
350 			}
351 			debug_reg_window = ml_io_map(base_address_pa, reg_window_size);
352 			assert(debug_reg_window);
353 			panic_trace_log("%s: %s: %#x bytes at %#lx mapped to %#lx\n",
354 			    __func__, entry_name, reg_window_size, base_address_pa, debug_reg_window );
355 		} else {
356 			if ((REGISTER_OFFSET(*reg_prop) + REGISTER_SIZE(*reg_prop)) > reg_window_size) {
357 				panic("%s: %s[%ld]: %#lx(+%lu)-byte offset from %#lx exceeds allocated size of %#x",
358 				    __func__, entry_name, next_command_buffer_entry - command_starting_index,
359 				    REGISTER_OFFSET(*reg_prop), REGISTER_SIZE(*reg_prop), base_address_pa, reg_window_size );
360 			}
361 
362 			if (next_command_buffer_entry - debug_command_buffer >= DEBUG_COMMAND_BUFFER_SIZE - 1) {
363 				// can't use the very last entry, since we need it to terminate the command
364 				panic("%s: %s[%ld]: out of space in command buffer",
365 				    __func__, entry_name, next_command_buffer_entry - command_starting_index );
366 			}
367 
368 			next_command_buffer_entry->address    = debug_reg_window + REGISTER_OFFSET(*reg_prop);
369 			next_command_buffer_entry->address_pa = base_address_pa  + REGISTER_OFFSET(*reg_prop);
370 			next_command_buffer_entry->value      = *(reg_prop + 1);
371 #if defined(__arm64__)
372 			next_command_buffer_entry->delay_us   = DELAY_US(*reg_prop);
373 			next_command_buffer_entry->is_32bit   = REGISTER_IS_32BIT(*reg_prop);
374 #else
375 			next_command_buffer_entry->delay_us   = 0;
376 			next_command_buffer_entry->is_32bit   = false;
377 #endif
378 			if ((next_command_buffer_entry->cpu_selector_is_range = CPU_SELECTOR_IS_RANGE(*reg_prop))) {
379 				next_command_buffer_entry->destination_cpu_selector.range.min_cpu = (uint8_t)CPU_SELECTOR_MIN_CPU(*reg_prop);
380 				next_command_buffer_entry->destination_cpu_selector.range.max_cpu = (uint8_t)CPU_SELECTOR_MAX_CPU(*reg_prop);
381 			} else {
382 				next_command_buffer_entry->destination_cpu_selector.mask = (uint16_t)CPU_SELECTOR(*reg_prop);
383 			}
384 			next_command_buffer_entry++;
385 		}
386 	}
387 
388 	// null terminate the address field of the command to end it
389 	(next_command_buffer_entry++)->address = 0;
390 
391 	// save pointer into table for this command
392 	*command_buffer = command_starting_index;
393 }
394 
395 static void
pe_run_debug_command(command_buffer_element_t * command_buffer)396 pe_run_debug_command(command_buffer_element_t *command_buffer)
397 {
398 	if (!PE_arm_debug_and_trace_initialized()) {
399 		/*
400 		 * In practice this can only happen if we panicked very early,
401 		 * when only the boot CPU is online and before it has finished
402 		 * initializing the debug and trace infrastructure. Avoid an
403 		 * unhelpful nested panic() here and instead resume execution
404 		 * to handle_debugger_trap(), which logs a user friendly error
405 		 * message before spinning forever.
406 		 */
407 		return;
408 	}
409 
410 	// When both the CPUs panic, one will get stuck on the lock and the other CPU will be halted when the first executes the debug command
411 	simple_lock(&panic_hook_lock, LCK_GRP_NULL);
412 
413 	running_debug_command_on_cpu_number = cpu_number();
414 
415 	while (command_buffer && command_buffer->address) {
416 		if (is_running_cpu_selected(command_buffer)) {
417 			panic_trace_log("%s: cpu %d: reg write 0x%lx (VA 0x%lx):= 0x%lx",
418 			    __func__, running_debug_command_on_cpu_number, command_buffer->address_pa,
419 			    command_buffer->address, command_buffer->value);
420 			if (command_buffer->is_32bit) {
421 				*((volatile uint32_t*)(command_buffer->address)) = (uint32_t)(command_buffer->value);
422 			} else {
423 				*((volatile uintptr_t*)(command_buffer->address)) = command_buffer->value;      // register = value;
424 			}
425 			if (command_buffer->delay_us != 0) {
426 				uint64_t deadline;
427 				nanoseconds_to_absolutetime(command_buffer->delay_us * NSEC_PER_USEC, &deadline);
428 				deadline += ml_get_timebase();
429 				while (ml_get_timebase() < deadline) {
430 					os_compiler_barrier();
431 				}
432 			}
433 		}
434 		command_buffer++;
435 	}
436 
437 	running_debug_command_on_cpu_number = -1;
438 	simple_unlock(&panic_hook_lock);
439 }
440 
441 void
PE_arm_debug_enable_trace(bool should_log)442 PE_arm_debug_enable_trace(bool should_log)
443 {
444 	if (should_log) {
445 		panic_trace_log("%s enter", __FUNCTION__);
446 	}
447 	if (panic_trace & panic_trace_enabled) {
448 		pe_run_debug_command(enable_trace);
449 	} else if (panic_trace & panic_trace_alt_enabled) {
450 		pe_run_debug_command(enable_alt_trace);
451 	}
452 	if (should_log) {
453 		panic_trace_log("%s exit", __FUNCTION__);
454 	}
455 }
456 
457 static void
PE_arm_panic_hook(const char * str __unused)458 PE_arm_panic_hook(const char *str __unused)
459 {
460 	(void)str; // not used
461 #if defined(__arm64__) && !APPLEVIRTUALPLATFORM
462 	/*
463 	 * For Fastsim support--inform the simulator that it can dump a
464 	 * panic trace now (so we don't capture all the panic handling).
465 	 * This constant is randomly chosen by agreement between xnu and
466 	 * Fastsim.
467 	 */
468 	__asm__ volatile ("hint #0x4f");
469 #endif /* defined(__arm64__) && !APPLEVIRTUALPLATFORM */
470 	if (bootarg_stop_clocks) {
471 		pe_run_debug_command(stop_clocks);
472 	}
473 	// disable panic trace to snapshot its ringbuffer
474 	// note: Not taking panic_trace_lock to avoid delaying cpu halt.
475 	//       This is known to be racy.
476 	if (panic_trace) {
477 		if (running_debug_command_on_cpu_number == cpu_number()) {
478 			// This is going to end badly if we don't trap, since we'd be panic-ing during our own code
479 			kprintf("## Panic Trace code caused the panic ##\n");
480 			return;  // allow the normal panic operation to occur.
481 		}
482 
483 		// Stop tracing to freeze the buffer and return to normal panic processing.
484 		pe_run_debug_command(trace_halt);
485 	}
486 }
487 
488 void (*PE_arm_debug_panic_hook)(const char *str) = PE_arm_panic_hook;
489 
490 void
PE_init_cpu(void)491 PE_init_cpu(void)
492 {
493 	if (bootarg_stop_clocks) {
494 		pe_run_debug_command(enable_stop_clocks);
495 	}
496 
497 	pe_init_fiq();
498 }
499 
500 #else
501 
502 void(*const PE_arm_debug_panic_hook)(const char *str) = NULL;
503 
504 void
PE_init_cpu(void)505 PE_init_cpu(void)
506 {
507 	pe_init_fiq();
508 }
509 
510 #endif  // DEVELOPMENT || DEBUG
511 
512 void
PE_singlestep_hook(void)513 PE_singlestep_hook(void)
514 {
515 }
516 
517 void
PE_panic_hook(const char * str __unused)518 PE_panic_hook(const char *str __unused)
519 {
520 	if (PE_arm_debug_panic_hook != NULL) {
521 		PE_arm_debug_panic_hook(str);
522 	}
523 }
524 
525 #if DEVELOPMENT || DEBUG
526 /*
527  * The % of devices which will have panic_trace enabled when using a partial
528  * enablement policy.
529  */
530 static TUNABLE_DT(uint32_t, panic_trace_partial_percent,
531     "/arm-io/cpu-debug-interface", "panic-trace-partial-percent",
532     "panic_trace_partial_percent", 50, TUNABLE_DT_NONE);
533 
534 /*
535  * When the `panic_trace_partial_policy` flag is set, not all devices will have
536  * the panic_trace settings applied. The actual % is determined by
537  * `panic_trace_partial_percent`.
538  * By using the ECID instead of a random number the process is made
539  * deterministic for any given device.
540  * This function disables panic trace if the device falls into the disabled %
541  * range. It otherwise leaves the panic_trace value unmodified.
542  * Called on the boot path, thus does not lock panic_trace_lock.
543  */
544 static void
panic_trace_apply_partial_policy(void)545 panic_trace_apply_partial_policy(void)
546 {
547 	assert3u((panic_trace & panic_trace_partial_policy), !=, 0);
548 
549 	DTEntry ent = NULL;
550 	unsigned int size = 0;
551 	const void *ecid = NULL;
552 
553 	/* Grab the ECID. */
554 	if (SecureDTLookupEntry(NULL, "/chosen", &ent) != kSuccess ||
555 	    SecureDTGetProperty(ent, "unique-chip-id", &ecid, &size) != kSuccess) {
556 		panic_trace = panic_trace_disabled;
557 		return;
558 	}
559 
560 	/*
561 	 * Use os_hash_jenkins to convert the decidedly non-random ECID into
562 	 * something resembling a random number. Better (cryptographic) hash
563 	 * functions are not available at this point in boot.
564 	 */
565 	const uint32_t rand = os_hash_jenkins(ecid, size);
566 
567 	/* Sanitize the percent value. */
568 	const uint32_t percent = MIN(100, panic_trace_partial_percent);
569 
570 	/*
571 	 * Apply the ECID percent value. The bias here should be so tiny as to not
572 	 * matter for this purpose.
573 	 */
574 	if ((rand % 100) >= percent) {
575 		panic_trace = panic_trace_disabled;
576 	}
577 }
578 #endif /* DEVELOPMENT || DEBUG */
579 
580 void
pe_arm_init_debug(void * args)581 pe_arm_init_debug(void *args)
582 {
583 	DTEntry         entryP;
584 	uintptr_t const *reg_prop;
585 	uint32_t        prop_size;
586 
587 	/*
588 	 * When args != NULL, this means we're being called from arm_init() on the
589 	 * boot CPU; this controls one-time init of the panic trace infrastructure.
590 	 * During one-time init, panic_trace_lock does not need to be held.
591 	 */
592 	const bool is_boot_cpu = (args != NULL);
593 
594 	if (gSocPhys == 0) {
595 		kprintf("pe_arm_init_debug: failed to initialize gSocPhys == 0\n");
596 		return;
597 	}
598 
599 #if DEVELOPMENT || DEBUG
600 	if (is_boot_cpu && (panic_trace & panic_trace_partial_policy) != 0) {
601 		panic_trace_apply_partial_policy();
602 	}
603 #endif /* DEVELOPMENT || DEBUG */
604 
605 	if (SecureDTFindEntry("device_type", "cpu-debug-interface", &entryP) == kSuccess) {
606 		if (is_boot_cpu) {
607 			if (SecureDTGetProperty(entryP, "reg", (void const **)&reg_prop, &prop_size) == kSuccess) {
608 				ml_init_arm_debug_interface(args, ml_io_map(gSocPhys + *reg_prop, *(reg_prop + 1)));
609 			}
610 #if DEVELOPMENT || DEBUG
611 			simple_lock_init(&panic_hook_lock, 0); //assuming single threaded mode
612 
613 			if (panic_trace) {
614 				kprintf("pe_arm_init_debug: panic_trace=%d\n", panic_trace);
615 
616 				// Prepare debug command buffers.
617 				pe_init_debug_command(entryP, &cpu_halt, "cpu_halt");
618 				pe_init_debug_command(entryP, &enable_trace, "enable_trace");
619 				pe_init_debug_command(entryP, &enable_alt_trace, "enable_alt_trace");
620 				pe_init_debug_command(entryP, &trace_halt, "trace_halt");
621 
622 				// start tracing now
623 				PE_arm_debug_enable_trace(true);
624 			}
625 			if (bootarg_stop_clocks) {
626 				pe_init_debug_command(entryP, &enable_stop_clocks, "enable_stop_clocks");
627 				pe_init_debug_command(entryP, &stop_clocks, "stop_clocks");
628 			}
629 #endif
630 		}
631 	} else {
632 #if DEVELOPMENT || DEBUG
633 		const uint32_t dependent_modes = (panic_trace_enabled | panic_trace_alt_enabled);
634 		if (is_boot_cpu && (bootarg_stop_clocks || (panic_trace & dependent_modes))) {
635 			panic("failed to find cpu-debug-interface node in the EDT! "
636 			    "(required by `panic_trace={0x01, 0x10}` or `stop_clocks=1`)");
637 		} else
638 #endif
639 		{
640 			kprintf("pe_arm_init_debug: failed to find cpu-debug-interface\n");
641 		}
642 	}
643 
644 
645 	debug_and_trace_initialized = true;
646 }
647 
648 static uint32_t
pe_arm_map_interrupt_controller(void)649 pe_arm_map_interrupt_controller(void)
650 {
651 	DTEntry         entryP;
652 	uintptr_t const *reg_prop;
653 	uint32_t        prop_size;
654 	vm_offset_t     soc_phys = 0;
655 
656 	gSocPhys = pe_arm_get_soc_base_phys();
657 
658 	soc_phys = gSocPhys;
659 	kprintf("pe_arm_map_interrupt_controller: soc_phys:  0x%lx\n", (unsigned long)soc_phys);
660 	if (soc_phys == 0) {
661 		return 0;
662 	}
663 
664 	if (SecureDTFindEntry("interrupt-controller", "master", &entryP) == kSuccess) {
665 		kprintf("pe_arm_map_interrupt_controller: found interrupt-controller\n");
666 		SecureDTGetProperty(entryP, "reg", (void const **)&reg_prop, &prop_size);
667 		gPicBase = ml_io_map(soc_phys + *reg_prop, *(reg_prop + 1));
668 		kprintf("pe_arm_map_interrupt_controller: gPicBase: 0x%lx\n", (unsigned long)gPicBase);
669 	}
670 	if (gPicBase == 0) {
671 		kprintf("pe_arm_map_interrupt_controller: failed to find the interrupt-controller.\n");
672 		return 0;
673 	}
674 
675 	if (SecureDTFindEntry("device_type", "timer", &entryP) == kSuccess) {
676 		kprintf("pe_arm_map_interrupt_controller: found timer\n");
677 		SecureDTGetProperty(entryP, "reg", (void const **)&reg_prop, &prop_size);
678 		gTimerBase = ml_io_map(soc_phys + *reg_prop, *(reg_prop + 1));
679 		kprintf("pe_arm_map_interrupt_controller: gTimerBase: 0x%lx\n", (unsigned long)gTimerBase);
680 	}
681 	if (gTimerBase == 0) {
682 		kprintf("pe_arm_map_interrupt_controller: failed to find the timer.\n");
683 		return 0;
684 	}
685 
686 	return 1;
687 }
688 
689 uint32_t
pe_arm_init_interrupts(void * args)690 pe_arm_init_interrupts(void *args)
691 {
692 	kprintf("pe_arm_init_interrupts: args: %p\n", args);
693 
694 	/* Set up mappings for interrupt controller and possibly timers (if they haven't been set up already) */
695 	if (args != NULL) {
696 		if (!pe_arm_map_interrupt_controller()) {
697 			return 0;
698 		}
699 	}
700 
701 	return pe_arm_init_timer(args);
702 }
703 
704 static uint32_t
pe_arm_init_timer(void * args)705 pe_arm_init_timer(void *args)
706 {
707 	vm_offset_t     pic_base = 0;
708 	vm_offset_t     timer_base = 0;
709 	vm_offset_t     soc_phys;
710 	vm_offset_t     eoi_addr = 0;
711 	uint32_t        eoi_value = 0;
712 	struct tbd_ops  generic_funcs = {&fleh_fiq_generic, NULL, NULL};
713 	struct tbd_ops  empty_funcs __unused = {NULL, NULL, NULL};
714 	tbd_ops_t       tbd_funcs = &generic_funcs;
715 
716 	/* The SoC headers expect to use pic_base, timer_base, etc... */
717 	pic_base = gPicBase;
718 	timer_base = gTimerBase;
719 	soc_phys = gSocPhys;
720 
721 #if defined(__arm64__)
722 	tbd_funcs = &empty_funcs;
723 #else
724 	return 0;
725 #endif
726 
727 	if (args != NULL) {
728 		ml_init_timebase(args, tbd_funcs, eoi_addr, eoi_value);
729 	}
730 
731 	return 1;
732 }
733