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 <machine/machine_routines.h>
14 #if DEVELOPMENT || DEBUG
15 #include <kern/simple_lock.h>
16 #include <kern/cpu_number.h>
17 #endif
18
19 #define PANIC_TRACE_LOG 1
20 #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); }
21 #if PANIC_TRACE_LOG
22 #define panic_trace_log(msg, args...) { if (panic_trace_debug) panic_trace_error(msg, ##args); }
23 #else
24 #define panic_trace_log(msg, args...)
25 #endif /* PANIC_TRACE_LOG */
26
27
28 /* Local declarations */
29 void pe_identify_machine(boot_args * bootArgs);
30
31 /* External declarations */
32 extern void clean_mmu_dcache(void);
33 extern void flush_dcache64(addr64_t addr, unsigned count, int phys);
34
35
36 static char *gPESoCDeviceType;
37 static char gPESoCDeviceTypeBuffer[SOC_DEVICE_TYPE_BUFFER_SIZE];
38 static vm_offset_t gPESoCBasePhys;
39
40 static uint32_t pe_arm_init_timer(void *args);
41
42 #if DEVELOPMENT || DEBUG
43 decl_simple_lock_data(, panic_hook_lock);
44 #endif
45 /*
46 * pe_identify_machine:
47 *
48 * Sets up platform parameters. Returns: nothing
49 */
50 void
pe_identify_machine(boot_args * bootArgs)51 pe_identify_machine(boot_args * bootArgs)
52 {
53 OpaqueDTEntryIterator iter;
54 DTEntry cpus, cpu;
55 void const *value;
56 unsigned int size;
57 int err;
58
59 (void)bootArgs;
60
61 if (pe_arm_get_soc_base_phys() == 0) {
62 return;
63 }
64
65 /* Clear the gPEClockFrequencyInfo struct */
66 bzero((void *)&gPEClockFrequencyInfo, sizeof(clock_frequency_info_t));
67
68 /* Start with default values. */
69 gPEClockFrequencyInfo.timebase_frequency_hz = 24000000;
70 gPEClockFrequencyInfo.bus_clock_rate_hz = 100000000;
71 gPEClockFrequencyInfo.cpu_clock_rate_hz = 400000000;
72
73 err = SecureDTLookupEntry(NULL, "/cpus", &cpus);
74 assert(err == kSuccess);
75
76 err = SecureDTInitEntryIterator(cpus, &iter);
77 assert(err == kSuccess);
78
79 while (kSuccess == SecureDTIterateEntries(&iter, &cpu)) {
80 if ((kSuccess != SecureDTGetProperty(cpu, "state", &value, &size)) ||
81 (strncmp((char const *)value, "running", size) != 0)) {
82 continue;
83 }
84
85 /* Find the time base frequency first. */
86 if (SecureDTGetProperty(cpu, "timebase-frequency", &value, &size) == kSuccess) {
87 /*
88 * timebase_frequency_hz is only 32 bits, and
89 * the device tree should never provide 64
90 * bits so this if should never be taken.
91 */
92 if (size == 8) {
93 gPEClockFrequencyInfo.timebase_frequency_hz = *(uint64_t const *)value;
94 } else {
95 gPEClockFrequencyInfo.timebase_frequency_hz = *(uint32_t const *)value;
96 }
97 }
98 gPEClockFrequencyInfo.dec_clock_rate_hz = gPEClockFrequencyInfo.timebase_frequency_hz;
99
100 /* Find the bus frequency next. */
101 if (SecureDTGetProperty(cpu, "bus-frequency", &value, &size) == kSuccess) {
102 if (size == 8) {
103 gPEClockFrequencyInfo.bus_frequency_hz = *(uint64_t const *)value;
104 } else {
105 gPEClockFrequencyInfo.bus_frequency_hz = *(uint32_t const *)value;
106 }
107 }
108 gPEClockFrequencyInfo.bus_frequency_min_hz = gPEClockFrequencyInfo.bus_frequency_hz;
109 gPEClockFrequencyInfo.bus_frequency_max_hz = gPEClockFrequencyInfo.bus_frequency_hz;
110
111 if (gPEClockFrequencyInfo.bus_frequency_hz < 0x100000000ULL) {
112 gPEClockFrequencyInfo.bus_clock_rate_hz = gPEClockFrequencyInfo.bus_frequency_hz;
113 } else {
114 gPEClockFrequencyInfo.bus_clock_rate_hz = 0xFFFFFFFF;
115 }
116
117 /* Find the memory frequency next. */
118 if (SecureDTGetProperty(cpu, "memory-frequency", &value, &size) == kSuccess) {
119 if (size == 8) {
120 gPEClockFrequencyInfo.mem_frequency_hz = *(uint64_t const *)value;
121 } else {
122 gPEClockFrequencyInfo.mem_frequency_hz = *(uint32_t const *)value;
123 }
124 }
125 gPEClockFrequencyInfo.mem_frequency_min_hz = gPEClockFrequencyInfo.mem_frequency_hz;
126 gPEClockFrequencyInfo.mem_frequency_max_hz = gPEClockFrequencyInfo.mem_frequency_hz;
127
128 /* Find the peripheral frequency next. */
129 if (SecureDTGetProperty(cpu, "peripheral-frequency", &value, &size) == kSuccess) {
130 if (size == 8) {
131 gPEClockFrequencyInfo.prf_frequency_hz = *(uint64_t const *)value;
132 } else {
133 gPEClockFrequencyInfo.prf_frequency_hz = *(uint32_t const *)value;
134 }
135 }
136 gPEClockFrequencyInfo.prf_frequency_min_hz = gPEClockFrequencyInfo.prf_frequency_hz;
137 gPEClockFrequencyInfo.prf_frequency_max_hz = gPEClockFrequencyInfo.prf_frequency_hz;
138
139 /* Find the fixed frequency next. */
140 if (SecureDTGetProperty(cpu, "fixed-frequency", &value, &size) == kSuccess) {
141 if (size == 8) {
142 gPEClockFrequencyInfo.fix_frequency_hz = *(uint64_t const *)value;
143 } else {
144 gPEClockFrequencyInfo.fix_frequency_hz = *(uint32_t const *)value;
145 }
146 }
147 /* Find the cpu frequency last. */
148 if (SecureDTGetProperty(cpu, "clock-frequency", &value, &size) == kSuccess) {
149 if (size == 8) {
150 gPEClockFrequencyInfo.cpu_frequency_hz = *(uint64_t const *)value;
151 } else {
152 gPEClockFrequencyInfo.cpu_frequency_hz = *(uint32_t const *)value;
153 }
154 }
155 gPEClockFrequencyInfo.cpu_frequency_min_hz = gPEClockFrequencyInfo.cpu_frequency_hz;
156 gPEClockFrequencyInfo.cpu_frequency_max_hz = gPEClockFrequencyInfo.cpu_frequency_hz;
157
158 if (gPEClockFrequencyInfo.cpu_frequency_hz < 0x100000000ULL) {
159 gPEClockFrequencyInfo.cpu_clock_rate_hz = gPEClockFrequencyInfo.cpu_frequency_hz;
160 } else {
161 gPEClockFrequencyInfo.cpu_clock_rate_hz = 0xFFFFFFFF;
162 }
163 }
164
165 /* Set the num / den pairs form the hz values. */
166 gPEClockFrequencyInfo.bus_clock_rate_num = gPEClockFrequencyInfo.bus_clock_rate_hz;
167 gPEClockFrequencyInfo.bus_clock_rate_den = 1;
168
169 gPEClockFrequencyInfo.bus_to_cpu_rate_num =
170 (2 * gPEClockFrequencyInfo.cpu_clock_rate_hz) / gPEClockFrequencyInfo.bus_clock_rate_hz;
171 gPEClockFrequencyInfo.bus_to_cpu_rate_den = 2;
172
173 gPEClockFrequencyInfo.bus_to_dec_rate_num = 1;
174 gPEClockFrequencyInfo.bus_to_dec_rate_den =
175 gPEClockFrequencyInfo.bus_clock_rate_hz / gPEClockFrequencyInfo.dec_clock_rate_hz;
176 }
177
178 vm_offset_t
pe_arm_get_soc_base_phys(void)179 pe_arm_get_soc_base_phys(void)
180 {
181 DTEntry entryP;
182 uintptr_t const *ranges_prop;
183 uint32_t prop_size;
184 char const *tmpStr;
185
186 if (SecureDTFindEntry("name", "arm-io", &entryP) == kSuccess) {
187 if (gPESoCDeviceType == 0) {
188 SecureDTGetProperty(entryP, "device_type", (void const **)&tmpStr, &prop_size);
189 strlcpy(gPESoCDeviceTypeBuffer, tmpStr, SOC_DEVICE_TYPE_BUFFER_SIZE);
190 gPESoCDeviceType = gPESoCDeviceTypeBuffer;
191
192 SecureDTGetProperty(entryP, "ranges", (void const **)&ranges_prop, &prop_size);
193 gPESoCBasePhys = *(ranges_prop + 1);
194 }
195 return gPESoCBasePhys;
196 }
197 return 0;
198 }
199
200 extern void fleh_fiq_generic(void);
201
202 vm_offset_t gPicBase;
203 vm_offset_t gTimerBase;
204 vm_offset_t gSocPhys;
205
206 #if DEVELOPMENT || DEBUG
207 // This block contains the panic trace implementation
208 TUNABLE_DT_WRITEABLE(panic_trace_t, panic_trace, "/arm-io/cpu-debug-interface", "panic-trace-mode", "panic_trace", panic_trace_disabled, TUNABLE_DT_NONE);
209 TUNABLE_WRITEABLE(boolean_t, panic_trace_debug, "panic_trace_debug", 1);
210 TUNABLE_WRITEABLE(uint64_t, panic_trace_core_cfg, "panic_trace_core_cfg", 0);
211 TUNABLE_WRITEABLE(uint64_t, panic_trace_ctl, "panic_trace_ctl", 0);
212 TUNABLE_WRITEABLE(uint64_t, panic_trace_pwr_state_ignore, "panic_trace_pwr_state_ignore", 0);
213 TUNABLE_WRITEABLE(boolean_t, panic_trace_experimental_hid, "panic_trace_experimental_hid", 0);
214 TUNABLE(unsigned int, bootarg_stop_clocks, "stop_clocks", 0);
215 extern unsigned int wfi;
216
217 // The command buffer contains the converted commands from the device tree for commanding cpu_halt, enable_trace, etc.
218 #define DEBUG_COMMAND_BUFFER_SIZE 256
219 typedef struct command_buffer_element {
220 uintptr_t address;
221 uintptr_t address_pa;
222 uintptr_t value;
223 union cpu_selector {
224 uint16_t mask;
225 struct cpu_range {
226 uint8_t min_cpu;
227 uint8_t max_cpu;
228 } range;
229 } destination_cpu_selector;
230 uint16_t delay_us;
231 bool cpu_selector_is_range;
232 bool is_32bit;
233 } command_buffer_element_t;
234
235 #define CPU_SELECTOR_SHIFT (16)
236 #define CPU_SELECTOR_MASK (0xFFFF << CPU_SELECTOR_SHIFT)
237 #define REGISTER_OFFSET_MASK ((1 << CPU_SELECTOR_SHIFT) - 1)
238 #define REGISTER_OFFSET(register_prop) (register_prop & REGISTER_OFFSET_MASK)
239 #define CPU_SELECTOR(register_offset) ((register_offset & CPU_SELECTOR_MASK) >> CPU_SELECTOR_SHIFT) // Upper 16bits holds the cpu selector
240 #define MAX_WINDOW_SIZE 0xFFFF
241 #define DELAY_SHIFT (32)
242 #define DELAY_MASK (0xFFFFULL << DELAY_SHIFT)
243 #define DELAY_US(register_offset) ((register_offset & DELAY_MASK) >> DELAY_SHIFT)
244 #define CPU_SELECTOR_ISRANGE_MASK (1ULL << 62)
245 #define REGISTER_32BIT_MASK (1ULL << 63)
246 #define ALL_CPUS 0x0000
247 #define RESET_VIRTUAL_ADDRESS_WINDOW 0xFFFFFFFF
248
249 #define REGISTER_IS_32BIT(register_offset) ((register_offset & REGISTER_32BIT_MASK) != 0)
250 #define REGISTER_SIZE(register_offset) (REGISTER_IS_32BIT(register_offset) ? sizeof(uint32_t) : sizeof(uintptr_t))
251 #define CPU_SELECTOR_IS_RANGE(register_offset) ((register_offset & CPU_SELECTOR_ISRANGE_MASK) != 0)
252 #define CPU_SELECTOR_MIN_CPU(register_offset) ((CPU_SELECTOR(register_offset) & 0xff00) >> 8)
253 #define CPU_SELECTOR_MAX_CPU(register_offset) (CPU_SELECTOR(register_offset) & 0x00ff)
254
255 // Record which CPU is currently running one of our debug commands, so we can trap panic reentrancy to PE_arm_debug_panic_hook.
256 static int running_debug_command_on_cpu_number = -1;
257
258 // Determine whether the current debug command is intended for this CPU.
259 static inline bool
is_running_cpu_selected(command_buffer_element_t * command)260 is_running_cpu_selected(command_buffer_element_t *command)
261 {
262 assert(running_debug_command_on_cpu_number >= 0);
263 if (command->cpu_selector_is_range) {
264 return running_debug_command_on_cpu_number >= command->destination_cpu_selector.range.min_cpu
265 && running_debug_command_on_cpu_number <= command->destination_cpu_selector.range.max_cpu;
266 } else if (command->destination_cpu_selector.mask == ALL_CPUS) {
267 return true;
268 } else {
269 return !!(command->destination_cpu_selector.mask & (1 << running_debug_command_on_cpu_number));
270 }
271 }
272
273
274 // Pointers into debug_command_buffer for each operation. Assumes runtime will init them to zero.
275 static command_buffer_element_t *cpu_halt;
276 static command_buffer_element_t *enable_trace;
277 static command_buffer_element_t *enable_alt_trace;
278 static command_buffer_element_t *trace_halt;
279 static command_buffer_element_t *enable_stop_clocks;
280 static command_buffer_element_t *stop_clocks;
281
282
283
284 /**************
285 * Public API *
286 **************/
287
288 static void
pe_init_debug_command(DTEntry entryP,command_buffer_element_t ** command_buffer,const char * entry_name)289 pe_init_debug_command(DTEntry entryP, command_buffer_element_t **command_buffer, const char* entry_name)
290 {
291 // statically allocate to prevent needing alloc at runtime
292 static command_buffer_element_t debug_command_buffer[DEBUG_COMMAND_BUFFER_SIZE];
293 static command_buffer_element_t *next_command_buffer_entry = debug_command_buffer;
294
295 // record this pointer but don't assign it to *command_buffer yet, in case we panic while half-initialized
296 command_buffer_element_t *command_starting_index = next_command_buffer_entry;
297
298 uintptr_t const *reg_prop;
299 uint32_t prop_size, reg_window_size = 0;
300 uintptr_t base_address_pa = 0, debug_reg_window = 0;
301
302 if (command_buffer == 0) {
303 panic_trace_log("%s: %s: no hook to assign this command to\n", __func__, entry_name);
304 return;
305 }
306
307 if (SecureDTGetProperty(entryP, entry_name, (void const **)®_prop, &prop_size) != kSuccess) {
308 panic("%s: %s: failed to read property from device tree", __func__, entry_name);
309 }
310
311 if (prop_size % (2 * sizeof(*reg_prop))) {
312 panic("%s: %s: property size %u bytes is not a multiple of %lu",
313 __func__, entry_name, prop_size, 2 * sizeof(*reg_prop));
314 }
315
316 // convert to real virt addresses and stuff commands into debug_command_buffer
317 for (; prop_size; reg_prop += 2, prop_size -= 2 * sizeof(*reg_prop)) {
318 if (*reg_prop == RESET_VIRTUAL_ADDRESS_WINDOW) {
319 debug_reg_window = 0; // Create a new window
320 } else if (debug_reg_window == 0) {
321 // create a window from virtual address to the specified physical address
322 base_address_pa = gSocPhys + *reg_prop;
323 reg_window_size = ((uint32_t)*(reg_prop + 1));
324 if (reg_window_size > MAX_WINDOW_SIZE) {
325 panic("%s: %s: %#x-byte window at #%lx exceeds maximum size of %#x",
326 __func__, entry_name, reg_window_size, base_address_pa, MAX_WINDOW_SIZE );
327 }
328 debug_reg_window = ml_io_map(base_address_pa, reg_window_size);
329 assert(debug_reg_window);
330 panic_trace_log("%s: %s: %#x bytes at %#lx mapped to %#lx\n",
331 __func__, entry_name, reg_window_size, base_address_pa, debug_reg_window );
332 } else {
333 if ((REGISTER_OFFSET(*reg_prop) + REGISTER_SIZE(*reg_prop)) > reg_window_size) {
334 panic("%s: %s[%ld]: %#lx(+%lu)-byte offset from %#lx exceeds allocated size of %#x",
335 __func__, entry_name, next_command_buffer_entry - command_starting_index,
336 REGISTER_OFFSET(*reg_prop), REGISTER_SIZE(*reg_prop), base_address_pa, reg_window_size );
337 }
338
339 if (next_command_buffer_entry - debug_command_buffer >= DEBUG_COMMAND_BUFFER_SIZE - 1) {
340 // can't use the very last entry, since we need it to terminate the command
341 panic("%s: %s[%ld]: out of space in command buffer",
342 __func__, entry_name, next_command_buffer_entry - command_starting_index );
343 }
344
345 next_command_buffer_entry->address = debug_reg_window + REGISTER_OFFSET(*reg_prop);
346 next_command_buffer_entry->address_pa = base_address_pa + REGISTER_OFFSET(*reg_prop);
347 next_command_buffer_entry->value = *(reg_prop + 1);
348 #if defined(__arm64__)
349 next_command_buffer_entry->delay_us = DELAY_US(*reg_prop);
350 next_command_buffer_entry->is_32bit = REGISTER_IS_32BIT(*reg_prop);
351 #else
352 next_command_buffer_entry->delay_us = 0;
353 next_command_buffer_entry->is_32bit = false;
354 #endif
355 if ((next_command_buffer_entry->cpu_selector_is_range = CPU_SELECTOR_IS_RANGE(*reg_prop))) {
356 next_command_buffer_entry->destination_cpu_selector.range.min_cpu = (uint8_t)CPU_SELECTOR_MIN_CPU(*reg_prop);
357 next_command_buffer_entry->destination_cpu_selector.range.max_cpu = (uint8_t)CPU_SELECTOR_MAX_CPU(*reg_prop);
358 } else {
359 next_command_buffer_entry->destination_cpu_selector.mask = (uint16_t)CPU_SELECTOR(*reg_prop);
360 }
361 next_command_buffer_entry++;
362 }
363 }
364
365 // null terminate the address field of the command to end it
366 (next_command_buffer_entry++)->address = 0;
367
368 // save pointer into table for this command
369 *command_buffer = command_starting_index;
370 }
371
372 static void
pe_run_debug_command(command_buffer_element_t * command_buffer)373 pe_run_debug_command(command_buffer_element_t *command_buffer)
374 {
375 // 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
376 simple_lock(&panic_hook_lock, LCK_GRP_NULL);
377
378 running_debug_command_on_cpu_number = cpu_number();
379
380 while (command_buffer && command_buffer->address) {
381 if (is_running_cpu_selected(command_buffer)) {
382 panic_trace_log("%s: cpu %d: reg write 0x%lx (VA 0x%lx):= 0x%lx",
383 __func__, running_debug_command_on_cpu_number, command_buffer->address_pa,
384 command_buffer->address, command_buffer->value);
385 if (command_buffer->is_32bit) {
386 *((volatile uint32_t*)(command_buffer->address)) = (uint32_t)(command_buffer->value);
387 } else {
388 *((volatile uintptr_t*)(command_buffer->address)) = command_buffer->value; // register = value;
389 }
390 if (command_buffer->delay_us != 0) {
391 uint64_t deadline;
392 nanoseconds_to_absolutetime(command_buffer->delay_us * NSEC_PER_USEC, &deadline);
393 deadline += ml_get_timebase();
394 while (ml_get_timebase() < deadline) {
395 os_compiler_barrier();
396 }
397 }
398 }
399 command_buffer++;
400 }
401
402 running_debug_command_on_cpu_number = -1;
403 simple_unlock(&panic_hook_lock);
404 }
405
406 void
PE_arm_debug_enable_trace(bool should_log)407 PE_arm_debug_enable_trace(bool should_log)
408 {
409 if (should_log) {
410 panic_trace_log("%s enter", __FUNCTION__);
411 }
412 if (panic_trace & panic_trace_enabled) {
413 pe_run_debug_command(enable_trace);
414 } else if (panic_trace & panic_trace_alt_enabled) {
415 pe_run_debug_command(enable_alt_trace);
416 }
417 if (should_log) {
418 panic_trace_log("%s exit", __FUNCTION__);
419 }
420 }
421
422 static void
PE_arm_panic_hook(const char * str __unused)423 PE_arm_panic_hook(const char *str __unused)
424 {
425 (void)str; // not used
426 if (bootarg_stop_clocks) {
427 pe_run_debug_command(stop_clocks);
428 }
429 // if panic trace is enabled
430 if (panic_trace) {
431 if (running_debug_command_on_cpu_number == cpu_number()) {
432 // This is going to end badly if we don't trap, since we'd be panic-ing during our own code
433 kprintf("## Panic Trace code caused the panic ##\n");
434 return; // allow the normal panic operation to occur.
435 }
436
437 // Stop tracing to freeze the buffer and return to normal panic processing.
438 pe_run_debug_command(trace_halt);
439 }
440 }
441
442 void (*PE_arm_debug_panic_hook)(const char *str) = PE_arm_panic_hook;
443
444 void
PE_init_cpu(void)445 PE_init_cpu(void)
446 {
447 if (bootarg_stop_clocks) {
448 pe_run_debug_command(enable_stop_clocks);
449 }
450
451 pe_init_fiq();
452 }
453
454 #else
455
456 void(*const PE_arm_debug_panic_hook)(const char *str) = NULL;
457
458 void
PE_init_cpu(void)459 PE_init_cpu(void)
460 {
461 pe_init_fiq();
462 }
463
464 #endif // DEVELOPMENT || DEBUG
465
466 void
PE_panic_hook(const char * str __unused)467 PE_panic_hook(const char *str __unused)
468 {
469 if (PE_arm_debug_panic_hook != NULL) {
470 PE_arm_debug_panic_hook(str);
471 }
472 }
473
474 void
pe_arm_init_debug(void * args)475 pe_arm_init_debug(void *args)
476 {
477 DTEntry entryP;
478 uintptr_t const *reg_prop;
479 uint32_t prop_size;
480
481 if (gSocPhys == 0) {
482 kprintf("pe_arm_init_debug: failed to initialize gSocPhys == 0\n");
483 return;
484 }
485
486 if (SecureDTFindEntry("device_type", "cpu-debug-interface", &entryP) == kSuccess) {
487 if (args != NULL) {
488 if (SecureDTGetProperty(entryP, "reg", (void const **)®_prop, &prop_size) == kSuccess) {
489 ml_init_arm_debug_interface(args, ml_io_map(gSocPhys + *reg_prop, *(reg_prop + 1)));
490 }
491 #if DEVELOPMENT || DEBUG
492 // When args != NULL, this means we're being called from arm_init on the boot CPU.
493 // This controls one-time initialization of the Panic Trace infrastructure
494
495 simple_lock_init(&panic_hook_lock, 0); //assuming single threaded mode
496
497 if (panic_trace) {
498 kprintf("pe_arm_init_debug: panic_trace=%d\n", panic_trace);
499
500 // Prepare debug command buffers.
501 pe_init_debug_command(entryP, &cpu_halt, "cpu_halt");
502 pe_init_debug_command(entryP, &enable_trace, "enable_trace");
503 pe_init_debug_command(entryP, &enable_alt_trace, "enable_alt_trace");
504 pe_init_debug_command(entryP, &trace_halt, "trace_halt");
505
506 // start tracing now
507 PE_arm_debug_enable_trace(true);
508 }
509 if (bootarg_stop_clocks) {
510 pe_init_debug_command(entryP, &enable_stop_clocks, "enable_stop_clocks");
511 pe_init_debug_command(entryP, &stop_clocks, "stop_clocks");
512 }
513 #endif
514 }
515 } else {
516 kprintf("pe_arm_init_debug: failed to find cpu-debug-interface\n");
517 }
518
519 }
520
521 static uint32_t
pe_arm_map_interrupt_controller(void)522 pe_arm_map_interrupt_controller(void)
523 {
524 DTEntry entryP;
525 uintptr_t const *reg_prop;
526 uint32_t prop_size;
527 vm_offset_t soc_phys = 0;
528
529 gSocPhys = pe_arm_get_soc_base_phys();
530
531 soc_phys = gSocPhys;
532 kprintf("pe_arm_map_interrupt_controller: soc_phys: 0x%lx\n", (unsigned long)soc_phys);
533 if (soc_phys == 0) {
534 return 0;
535 }
536
537 if (SecureDTFindEntry("interrupt-controller", "master", &entryP) == kSuccess) {
538 kprintf("pe_arm_map_interrupt_controller: found interrupt-controller\n");
539 SecureDTGetProperty(entryP, "reg", (void const **)®_prop, &prop_size);
540 gPicBase = ml_io_map(soc_phys + *reg_prop, *(reg_prop + 1));
541 kprintf("pe_arm_map_interrupt_controller: gPicBase: 0x%lx\n", (unsigned long)gPicBase);
542 }
543 if (gPicBase == 0) {
544 kprintf("pe_arm_map_interrupt_controller: failed to find the interrupt-controller.\n");
545 return 0;
546 }
547
548 if (SecureDTFindEntry("device_type", "timer", &entryP) == kSuccess) {
549 kprintf("pe_arm_map_interrupt_controller: found timer\n");
550 SecureDTGetProperty(entryP, "reg", (void const **)®_prop, &prop_size);
551 gTimerBase = ml_io_map(soc_phys + *reg_prop, *(reg_prop + 1));
552 kprintf("pe_arm_map_interrupt_controller: gTimerBase: 0x%lx\n", (unsigned long)gTimerBase);
553 }
554 if (gTimerBase == 0) {
555 kprintf("pe_arm_map_interrupt_controller: failed to find the timer.\n");
556 return 0;
557 }
558
559 return 1;
560 }
561
562 uint32_t
pe_arm_init_interrupts(void * args)563 pe_arm_init_interrupts(void *args)
564 {
565 kprintf("pe_arm_init_interrupts: args: %p\n", args);
566
567 /* Set up mappings for interrupt controller and possibly timers (if they haven't been set up already) */
568 if (args != NULL) {
569 if (!pe_arm_map_interrupt_controller()) {
570 return 0;
571 }
572 }
573
574 return pe_arm_init_timer(args);
575 }
576
577 static uint32_t
pe_arm_init_timer(void * args)578 pe_arm_init_timer(void *args)
579 {
580 vm_offset_t pic_base = 0;
581 vm_offset_t timer_base = 0;
582 vm_offset_t soc_phys;
583 vm_offset_t eoi_addr = 0;
584 uint32_t eoi_value = 0;
585 struct tbd_ops generic_funcs = {&fleh_fiq_generic, NULL, NULL};
586 struct tbd_ops empty_funcs __unused = {NULL, NULL, NULL};
587 tbd_ops_t tbd_funcs = &generic_funcs;
588
589 /* The SoC headers expect to use pic_base, timer_base, etc... */
590 pic_base = gPicBase;
591 timer_base = gTimerBase;
592 soc_phys = gSocPhys;
593
594 #if defined(__arm64__)
595 tbd_funcs = &empty_funcs;
596 #else
597 return 0;
598 #endif
599
600 if (args != NULL) {
601 ml_init_timebase(args, tbd_funcs, eoi_addr, eoi_value);
602 }
603
604 return 1;
605 }
606