]> git.saurik.com Git - apple/xnu.git/blob - pexpert/arm/pe_init.c
8ff54da6c1c9ac1981cf63d26be0e6f375c20aac
[apple/xnu.git] / pexpert / arm / pe_init.c
1 /*
2 * Copyright (c) 2000-2017 Apple Inc. All rights reserved.
3 *
4 * arm platform expert initialization.
5 */
6 #include <sys/types.h>
7 #include <sys/kdebug.h>
8 #include <mach/vm_param.h>
9 #include <pexpert/protos.h>
10 #include <pexpert/pexpert.h>
11 #include <pexpert/boot.h>
12 #include <pexpert/device_tree.h>
13 #include <pexpert/pe_images.h>
14 #include <kern/sched_prim.h>
15 #include <machine/machine_routines.h>
16 #include <arm/caches_internal.h>
17 #include <kern/debug.h>
18 #include <libkern/section_keywords.h>
19
20 #if defined __arm__
21 #include <pexpert/arm/board_config.h>
22 #elif defined __arm64__
23 #include <pexpert/arm64/board_config.h>
24 #endif
25
26
27 /* extern references */
28 extern void pe_identify_machine(boot_args *bootArgs);
29
30 /* static references */
31 static void pe_prepare_images(void);
32
33 /* private globals */
34 SECURITY_READ_ONLY_LATE(PE_state_t) PE_state;
35 #define FW_VERS_LEN 128
36 char firmware_version[FW_VERS_LEN];
37
38 /*
39 * This variable is only modified once, when the BSP starts executing. We put it in __TEXT
40 * as page protections on kernel text early in startup are read-write. The kernel is
41 * locked down later in start-up, said mappings become RO and thus this
42 * variable becomes immutable.
43 *
44 * See osfmk/arm/arm_vm_init.c for more information.
45 */
46 SECURITY_READ_ONLY_SPECIAL_SECTION(volatile uint32_t, "__TEXT,__const") debug_enabled = FALSE;
47
48 uint8_t gPlatformECID[8];
49 uint32_t gPlatformMemoryID;
50 static boolean_t vc_progress_initialized = FALSE;
51 uint64_t last_hwaccess_thread = 0;
52 char gTargetTypeBuffer[16];
53 char gModelTypeBuffer[32];
54
55 /* Clock Frequency Info */
56 clock_frequency_info_t gPEClockFrequencyInfo;
57
58 vm_offset_t gPanicBase = 0;
59 unsigned int gPanicSize;
60 struct embedded_panic_header *panic_info = NULL;
61
62 #if (DEVELOPMENT || DEBUG) && defined(XNU_TARGET_OS_BRIDGE)
63 /*
64 * On DEVELOPMENT bridgeOS, we map the x86 panic region
65 * so we can include this data in bridgeOS corefiles
66 */
67 uint64_t macos_panic_base = 0;
68 unsigned int macos_panic_size = 0;
69
70 struct macos_panic_header *mac_panic_header = NULL;
71 #endif
72
73 /* Maximum size of panic log excluding headers, in bytes */
74 static unsigned int panic_text_len;
75
76 /* Whether a console is standing by for panic logging */
77 static boolean_t panic_console_available = FALSE;
78
79 extern uint32_t crc32(uint32_t crc, const void *buf, size_t size);
80
81 void PE_slide_devicetree(vm_offset_t);
82
83 static void
84 check_for_panic_log(void)
85 {
86 #ifdef PLATFORM_PANIC_LOG_PADDR
87 gPanicBase = ml_io_map_wcomb(PLATFORM_PANIC_LOG_PADDR, PLATFORM_PANIC_LOG_SIZE);
88 panic_text_len = PLATFORM_PANIC_LOG_SIZE - sizeof(struct embedded_panic_header);
89 gPanicSize = PLATFORM_PANIC_LOG_SIZE;
90 #else
91 DTEntry entry, chosen;
92 unsigned int size;
93 uintptr_t const *reg_prop;
94 uint32_t const *panic_region_length;
95
96 /*
97 * DT properties for the panic region are populated by UpdateDeviceTree() in iBoot:
98 *
99 * chosen {
100 * embedded-panic-log-size = <0x00080000>;
101 * [a bunch of other stuff]
102 * };
103 *
104 * pram {
105 * reg = <0x00000008_fbc48000 0x00000000_000b4000>;
106 * };
107 *
108 * reg[0] is the physical address
109 * reg[1] is the size of iBoot's kMemoryRegion_Panic (not used)
110 * embedded-panic-log-size is the maximum amount of data to store in the buffer
111 */
112 if (kSuccess != SecureDTLookupEntry(0, "pram", &entry)) {
113 return;
114 }
115
116 if (kSuccess != SecureDTGetProperty(entry, "reg", (void const **)&reg_prop, &size)) {
117 return;
118 }
119
120 if (kSuccess != SecureDTLookupEntry(0, "/chosen", &chosen)) {
121 return;
122 }
123
124 if (kSuccess != SecureDTGetProperty(chosen, "embedded-panic-log-size", (void const **) &panic_region_length, &size)) {
125 return;
126 }
127
128 gPanicBase = ml_io_map_wcomb(reg_prop[0], panic_region_length[0]);
129
130 /* Deduct the size of the panic header from the panic region size */
131 panic_text_len = panic_region_length[0] - sizeof(struct embedded_panic_header);
132 gPanicSize = panic_region_length[0];
133
134 #if DEVELOPMENT && defined(XNU_TARGET_OS_BRIDGE)
135 if (PE_consistent_debug_enabled()) {
136 uint64_t macos_panic_physbase = 0;
137 uint64_t macos_panic_physlen = 0;
138 /* Populate the macOS panic region data if it's present in consistent debug */
139 if (PE_consistent_debug_lookup_entry(kDbgIdMacOSPanicRegion, &macos_panic_physbase, &macos_panic_physlen)) {
140 macos_panic_base = ml_io_map_with_prot(macos_panic_physbase, macos_panic_physlen, VM_PROT_READ);
141 mac_panic_header = (struct macos_panic_header *) ((void *) macos_panic_base);
142 macos_panic_size = macos_panic_physlen;
143 }
144 }
145 #endif /* DEVELOPMENT && defined(XNU_TARGET_OS_BRIDGE) */
146
147 #endif
148 panic_info = (struct embedded_panic_header *)gPanicBase;
149
150 /* Check if a shared memory console is running in the panic buffer */
151 if (panic_info->eph_magic == 'SHMC') {
152 panic_console_available = TRUE;
153 return;
154 }
155
156 /* Check if there's a boot profile in the panic buffer */
157 if (panic_info->eph_magic == 'BTRC') {
158 return;
159 }
160
161 /*
162 * Check to see if a panic (FUNK) is in VRAM from the last time
163 */
164 if (panic_info->eph_magic == EMBEDDED_PANIC_MAGIC) {
165 printf("iBoot didn't extract panic log from previous session crash, this is bad\n");
166 }
167
168 /* Clear panic region */
169 bzero((void *)gPanicBase, gPanicSize);
170 }
171
172 int
173 PE_initialize_console(PE_Video * info, int op)
174 {
175 static int last_console = -1;
176
177 if (info && (info != &PE_state.video)) {
178 info->v_scale = PE_state.video.v_scale;
179 }
180
181 switch (op) {
182 case kPEDisableScreen:
183 initialize_screen(info, op);
184 last_console = switch_to_serial_console();
185 kprintf("kPEDisableScreen %d\n", last_console);
186 break;
187
188 case kPEEnableScreen:
189 initialize_screen(info, op);
190 if (info) {
191 PE_state.video = *info;
192 }
193 kprintf("kPEEnableScreen %d\n", last_console);
194 if (last_console != -1) {
195 switch_to_old_console(last_console);
196 }
197 break;
198
199 case kPEReleaseScreen:
200 /*
201 * we don't show the progress indicator on boot, but want to
202 * show it afterwards.
203 */
204 if (!vc_progress_initialized) {
205 default_progress.dx = 0;
206 default_progress.dy = 0;
207 vc_progress_initialize(&default_progress,
208 default_progress_data1x,
209 default_progress_data2x,
210 default_progress_data3x,
211 (unsigned char *) appleClut8);
212 vc_progress_initialized = TRUE;
213 }
214 initialize_screen(info, op);
215 break;
216
217 default:
218 initialize_screen(info, op);
219 break;
220 }
221
222 return 0;
223 }
224
225 void
226 PE_init_iokit(void)
227 {
228 DTEntry entry;
229 unsigned int size, scale;
230 unsigned long display_size;
231 void const * const *map;
232 unsigned int show_progress;
233 int *delta, image_size, flip;
234 uint32_t start_time_value = 0;
235 uint32_t debug_wait_start_value = 0;
236 uint32_t load_kernel_start_value = 0;
237 uint32_t populate_registry_time_value = 0;
238
239 PE_init_printf(TRUE);
240
241 printf("iBoot version: %s\n", firmware_version);
242
243 if (kSuccess == SecureDTLookupEntry(0, "/chosen/memory-map", &entry)) {
244 boot_progress_element const *bootPict;
245
246 if (kSuccess == SecureDTGetProperty(entry, "BootCLUT", (void const **) &map, &size)) {
247 bcopy(map[0], appleClut8, sizeof(appleClut8));
248 }
249
250 if (kSuccess == SecureDTGetProperty(entry, "Pict-FailedBoot", (void const **) &map, &size)) {
251 bootPict = (boot_progress_element const *) map[0];
252 default_noroot.width = bootPict->width;
253 default_noroot.height = bootPict->height;
254 default_noroot.dx = 0;
255 default_noroot.dy = bootPict->yOffset;
256 default_noroot_data = &bootPict->data[0];
257 }
258 }
259
260 pe_prepare_images();
261
262 scale = PE_state.video.v_scale;
263 flip = 1;
264
265 #if defined(XNU_TARGET_OS_OSX)
266 int notused;
267 show_progress = TRUE;
268 if (PE_parse_boot_argn("-restore", &notused, sizeof(notused))) {
269 show_progress = FALSE;
270 }
271 if (PE_parse_boot_argn("-noprogress", &notused, sizeof(notused))) {
272 show_progress = FALSE;
273 }
274 #else
275 show_progress = FALSE;
276 PE_parse_boot_argn("-progress", &show_progress, sizeof(show_progress));
277 #endif /* XNU_TARGET_OS_OSX */
278 if (show_progress) {
279 /* Rotation: 0:normal, 1:right 90, 2:left 180, 3:left 90 */
280 switch (PE_state.video.v_rotate) {
281 case 2:
282 flip = -1;
283 OS_FALLTHROUGH;
284 case 0:
285 display_size = PE_state.video.v_height;
286 image_size = default_progress.height;
287 delta = &default_progress.dy;
288 break;
289 case 1:
290 flip = -1;
291 OS_FALLTHROUGH;
292 case 3:
293 default:
294 display_size = PE_state.video.v_width;
295 image_size = default_progress.width;
296 delta = &default_progress.dx;
297 }
298 assert(*delta >= 0);
299 while (((unsigned)(*delta + image_size)) >= (display_size / 2)) {
300 *delta -= 50 * scale;
301 assert(*delta >= 0);
302 }
303 *delta *= flip;
304
305 /* Check for DT-defined progress y delta */
306 PE_get_default("progress-dy", &default_progress.dy, sizeof(default_progress.dy));
307
308 vc_progress_initialize(&default_progress,
309 default_progress_data1x,
310 default_progress_data2x,
311 default_progress_data3x,
312 (unsigned char *) appleClut8);
313 vc_progress_initialized = TRUE;
314 }
315
316 if (kdebug_enable && kdebug_debugid_enabled(IOKDBG_CODE(DBG_BOOTER, 0))) {
317 /* Trace iBoot-provided timing information. */
318 if (kSuccess == SecureDTLookupEntry(0, "/chosen/iBoot", &entry)) {
319 uint32_t const * value_ptr;
320
321 if (kSuccess == SecureDTGetProperty(entry, "start-time", (void const **)&value_ptr, &size)) {
322 if (size == sizeof(start_time_value)) {
323 start_time_value = *value_ptr;
324 }
325 }
326
327 if (kSuccess == SecureDTGetProperty(entry, "debug-wait-start", (void const **)&value_ptr, &size)) {
328 if (size == sizeof(debug_wait_start_value)) {
329 debug_wait_start_value = *value_ptr;
330 }
331 }
332
333 if (kSuccess == SecureDTGetProperty(entry, "load-kernel-start", (void const **)&value_ptr, &size)) {
334 if (size == sizeof(load_kernel_start_value)) {
335 load_kernel_start_value = *value_ptr;
336 }
337 }
338
339 if (kSuccess == SecureDTGetProperty(entry, "populate-registry-time", (void const **)&value_ptr, &size)) {
340 if (size == sizeof(populate_registry_time_value)) {
341 populate_registry_time_value = *value_ptr;
342 }
343 }
344 }
345
346 KDBG_RELEASE(IOKDBG_CODE(DBG_BOOTER, 0), start_time_value, debug_wait_start_value, load_kernel_start_value, populate_registry_time_value);
347 }
348
349 InitIOKit(PE_state.deviceTreeHead);
350 ConfigureIOKit();
351 }
352
353 void
354 PE_lockdown_iokit(void)
355 {
356 /*
357 * On arm/arm64 platforms, and especially those that employ KTRR/CTRR,
358 * machine_lockdown() is treated as a hard security checkpoint, such that
359 * code which executes prior to lockdown must be minimized and limited only to
360 * trusted parts of the kernel and specially-entitled kexts. We therefore
361 * cannot start the general-purpose IOKit matching process until after lockdown,
362 * as it may involve execution of untrusted/non-entitled kext code.
363 * Furthermore, such kext code may process attacker controlled data (e.g.
364 * network packets), which dramatically increases the potential attack surface
365 * against a kernel which has not yet enabled the full set of available
366 * hardware protections.
367 */
368 StartIOKitMatching();
369 }
370
371 void
372 PE_slide_devicetree(vm_offset_t slide)
373 {
374 assert(PE_state.initialized);
375 PE_state.deviceTreeHead += slide;
376 SecureDTInit(PE_state.deviceTreeHead, PE_state.deviceTreeSize);
377 }
378
379 void
380 PE_init_platform(boolean_t vm_initialized, void *args)
381 {
382 DTEntry entry;
383 unsigned int size;
384 void * const *prop;
385 boot_args *boot_args_ptr = (boot_args *) args;
386
387 if (PE_state.initialized == FALSE) {
388 PE_state.initialized = TRUE;
389 PE_state.bootArgs = boot_args_ptr;
390 PE_state.deviceTreeHead = boot_args_ptr->deviceTreeP;
391 PE_state.deviceTreeSize = boot_args_ptr->deviceTreeLength;
392 PE_state.video.v_baseAddr = boot_args_ptr->Video.v_baseAddr;
393 PE_state.video.v_rowBytes = boot_args_ptr->Video.v_rowBytes;
394 PE_state.video.v_width = boot_args_ptr->Video.v_width;
395 PE_state.video.v_height = boot_args_ptr->Video.v_height;
396 PE_state.video.v_depth = (boot_args_ptr->Video.v_depth >> kBootVideoDepthDepthShift) & kBootVideoDepthMask;
397 PE_state.video.v_rotate = (boot_args_ptr->Video.v_depth >> kBootVideoDepthRotateShift) & kBootVideoDepthMask;
398 PE_state.video.v_scale = ((boot_args_ptr->Video.v_depth >> kBootVideoDepthScaleShift) & kBootVideoDepthMask) + 1;
399 PE_state.video.v_display = boot_args_ptr->Video.v_display;
400 strlcpy(PE_state.video.v_pixelFormat, "BBBBBBBBGGGGGGGGRRRRRRRR", sizeof(PE_state.video.v_pixelFormat));
401 }
402 if (!vm_initialized) {
403 /*
404 * Setup the Device Tree routines
405 * so the console can be found and the right I/O space
406 * can be used..
407 */
408 SecureDTInit(PE_state.deviceTreeHead, PE_state.deviceTreeSize);
409 pe_identify_machine(boot_args_ptr);
410 } else {
411 pe_arm_init_interrupts(args);
412 pe_arm_init_debug(args);
413 }
414
415 if (!vm_initialized) {
416 if (kSuccess == (SecureDTFindEntry("name", "device-tree", &entry))) {
417 if (kSuccess == SecureDTGetProperty(entry, "target-type",
418 (void const **)&prop, &size)) {
419 if (size > sizeof(gTargetTypeBuffer)) {
420 size = sizeof(gTargetTypeBuffer);
421 }
422 bcopy(prop, gTargetTypeBuffer, size);
423 gTargetTypeBuffer[size - 1] = '\0';
424 }
425 }
426 if (kSuccess == (SecureDTFindEntry("name", "device-tree", &entry))) {
427 if (kSuccess == SecureDTGetProperty(entry, "model",
428 (void const **)&prop, &size)) {
429 if (size > sizeof(gModelTypeBuffer)) {
430 size = sizeof(gModelTypeBuffer);
431 }
432 bcopy(prop, gModelTypeBuffer, size);
433 gModelTypeBuffer[size - 1] = '\0';
434 }
435 }
436 if (kSuccess == SecureDTLookupEntry(NULL, "/chosen", &entry)) {
437 if (kSuccess == SecureDTGetProperty(entry, "debug-enabled",
438 (void const **) &prop, &size)) {
439 /*
440 * We purposefully modify a constified variable as
441 * it will get locked down by a trusted monitor or
442 * via page table mappings. We don't want people easily
443 * modifying this variable...
444 */
445 #pragma clang diagnostic push
446 #pragma clang diagnostic ignored "-Wcast-qual"
447 boolean_t *modify_debug_enabled = (boolean_t *) &debug_enabled;
448 if (size > sizeof(uint32_t)) {
449 size = sizeof(uint32_t);
450 }
451 bcopy(prop, modify_debug_enabled, size);
452 #pragma clang diagnostic pop
453 }
454 if (kSuccess == SecureDTGetProperty(entry, "firmware-version",
455 (void const **) &prop, &size)) {
456 if (size > sizeof(firmware_version)) {
457 size = sizeof(firmware_version);
458 }
459 bcopy(prop, firmware_version, size);
460 firmware_version[size - 1] = '\0';
461 }
462 if (kSuccess == SecureDTGetProperty(entry, "unique-chip-id",
463 (void const **) &prop, &size)) {
464 if (size > sizeof(gPlatformECID)) {
465 size = sizeof(gPlatformECID);
466 }
467 bcopy(prop, gPlatformECID, size);
468 }
469 if (kSuccess == SecureDTGetProperty(entry, "dram-vendor-id",
470 (void const **) &prop, &size)) {
471 if (size > sizeof(gPlatformMemoryID)) {
472 size = sizeof(gPlatformMemoryID);
473 }
474 bcopy(prop, &gPlatformMemoryID, size);
475 }
476 }
477 pe_init_debug();
478 }
479 }
480
481 void
482 PE_create_console(void)
483 {
484 /*
485 * Check the head of VRAM for a panic log saved on last panic.
486 * Do this before the VRAM is trashed.
487 */
488 check_for_panic_log();
489
490 if (PE_state.video.v_display) {
491 PE_initialize_console(&PE_state.video, kPEGraphicsMode);
492 } else {
493 PE_initialize_console(&PE_state.video, kPETextMode);
494 }
495 }
496
497 int
498 PE_current_console(PE_Video * info)
499 {
500 *info = PE_state.video;
501 return 0;
502 }
503
504 void
505 PE_display_icon(__unused unsigned int flags, __unused const char *name)
506 {
507 if (default_noroot_data) {
508 vc_display_icon(&default_noroot, default_noroot_data);
509 }
510 }
511
512 extern boolean_t
513 PE_get_hotkey(__unused unsigned char key)
514 {
515 return FALSE;
516 }
517
518 static timebase_callback_func gTimebaseCallback;
519
520 void
521 PE_register_timebase_callback(timebase_callback_func callback)
522 {
523 gTimebaseCallback = callback;
524
525 PE_call_timebase_callback();
526 }
527
528 void
529 PE_call_timebase_callback(void)
530 {
531 struct timebase_freq_t timebase_freq;
532
533 timebase_freq.timebase_num = gPEClockFrequencyInfo.timebase_frequency_hz;
534 timebase_freq.timebase_den = 1;
535
536 if (gTimebaseCallback) {
537 gTimebaseCallback(&timebase_freq);
538 }
539 }
540
541 /*
542 * The default PE_poll_input handler.
543 */
544 int
545 PE_stub_poll_input(__unused unsigned int options, char *c)
546 {
547 *c = (char)uart_getc();
548 return 0; /* 0 for success, 1 for unsupported */
549 }
550
551 /*
552 * This routine will return 1 if you are running on a device with a variant
553 * of iBoot that allows debugging. This is typically not the case on production
554 * fused parts (even when running development variants of iBoot).
555 *
556 * The routine takes an optional argument of the flags passed to debug="" so
557 * kexts don't have to parse the boot arg themselves.
558 */
559 uint32_t
560 PE_i_can_has_debugger(uint32_t *debug_flags)
561 {
562 if (debug_flags) {
563 #if DEVELOPMENT || DEBUG
564 assert(startup_phase >= STARTUP_SUB_TUNABLES);
565 #endif
566 if (debug_enabled) {
567 *debug_flags = debug_boot_arg;
568 } else {
569 *debug_flags = 0;
570 }
571 }
572 return debug_enabled;
573 }
574
575 /*
576 * This routine returns TRUE if the device is configured
577 * with panic debugging enabled.
578 */
579 boolean_t
580 PE_panic_debugging_enabled()
581 {
582 return panicDebugging;
583 }
584
585 void
586 PE_save_buffer_to_vram(unsigned char *buf, unsigned int *size)
587 {
588 if (!panic_info || !size) {
589 return;
590 }
591
592 if (!buf) {
593 *size = panic_text_len;
594 return;
595 }
596
597 if (*size == 0) {
598 return;
599 }
600
601 *size = *size > panic_text_len ? panic_text_len : *size;
602 if (panic_info->eph_magic != EMBEDDED_PANIC_MAGIC) {
603 printf("Error!! Current Magic 0x%X, expected value 0x%x", panic_info->eph_magic, EMBEDDED_PANIC_MAGIC);
604 }
605
606 /* CRC everything after the CRC itself - starting with the panic header version */
607 panic_info->eph_crc = crc32(0L, &panic_info->eph_version, (panic_text_len +
608 sizeof(struct embedded_panic_header) - offsetof(struct embedded_panic_header, eph_version)));
609 }
610
611 uint32_t
612 PE_get_offset_into_panic_region(char *location)
613 {
614 assert(gPanicBase != 0);
615 assert(location >= (char *) gPanicBase);
616 assert((unsigned int)(location - gPanicBase) < gPanicSize);
617
618 return (uint32_t)(uintptr_t)(location - gPanicBase);
619 }
620
621 void
622 PE_init_panicheader()
623 {
624 if (!panic_info) {
625 return;
626 }
627
628 bzero(panic_info, sizeof(struct embedded_panic_header));
629
630 /*
631 * The panic log begins immediately after the panic header -- debugger synchronization and other functions
632 * may log into this region before we've become the exclusive panicking CPU and initialize the header here.
633 */
634 panic_info->eph_panic_log_offset = debug_buf_base ? PE_get_offset_into_panic_region(debug_buf_base) : 0;
635
636 panic_info->eph_magic = EMBEDDED_PANIC_MAGIC;
637 panic_info->eph_version = EMBEDDED_PANIC_HEADER_CURRENT_VERSION;
638
639 return;
640 }
641
642 /*
643 * Tries to update the panic header to keep it consistent on nested panics.
644 *
645 * NOTE: The purpose of this function is NOT to detect/correct corruption in the panic region,
646 * it is to update the panic header to make it consistent when we nest panics.
647 */
648 void
649 PE_update_panicheader_nestedpanic()
650 {
651 if (!panic_info) {
652 return;
653 }
654
655 /*
656 * If the panic log offset is not set, re-init the panic header
657 */
658 if (panic_info->eph_panic_log_offset == 0) {
659 PE_init_panicheader();
660 panic_info->eph_panic_flags |= EMBEDDED_PANIC_HEADER_FLAG_NESTED_PANIC;
661 return;
662 }
663
664 panic_info->eph_panic_flags |= EMBEDDED_PANIC_HEADER_FLAG_NESTED_PANIC;
665
666 /*
667 * If the panic log length is not set, set the end to
668 * the current location of the debug_buf_ptr to close it.
669 */
670 if (panic_info->eph_panic_log_len == 0) {
671 panic_info->eph_panic_log_len = PE_get_offset_into_panic_region(debug_buf_ptr);
672
673 /* If this assert fires, it's indicative of corruption in the panic region */
674 assert(panic_info->eph_other_log_offset == panic_info->eph_other_log_len == 0);
675 }
676
677 /* If this assert fires, it's likely indicative of corruption in the panic region */
678 assert(((panic_info->eph_stackshot_offset == 0) && (panic_info->eph_stackshot_len == 0)) ||
679 ((panic_info->eph_stackshot_offset != 0) && (panic_info->eph_stackshot_len != 0)));
680
681 /*
682 * If we haven't set up the other log yet, set the beginning of the other log
683 * to the current location of the debug_buf_ptr
684 */
685 if (panic_info->eph_other_log_offset == 0) {
686 panic_info->eph_other_log_offset = PE_get_offset_into_panic_region(debug_buf_ptr);
687
688 /* If this assert fires, it's indicative of corruption in the panic region */
689 assert(panic_info->eph_other_log_len == 0);
690 }
691
692 return;
693 }
694
695 boolean_t
696 PE_reboot_on_panic(void)
697 {
698 uint32_t debug_flags;
699
700 if (PE_i_can_has_debugger(&debug_flags)
701 && (debug_flags & DB_NMI)) {
702 /* kernel debugging is active */
703 return FALSE;
704 } else {
705 return TRUE;
706 }
707 }
708
709 void
710 PE_sync_panic_buffers(void)
711 {
712 /*
713 * rdar://problem/26453070:
714 * The iBoot panic region is write-combined on arm64. We must flush dirty lines
715 * from L1/L2 as late as possible before reset, with no further reads of the panic
716 * region between the flush and the reset. Some targets have an additional memcache (L3),
717 * and a read may bring dirty lines out of L3 and back into L1/L2, causing the lines to
718 * be discarded on reset. If we can make sure the lines are flushed to L3/DRAM,
719 * the platform reset handler will flush any L3.
720 */
721 if (gPanicBase) {
722 CleanPoC_DcacheRegion_Force(gPanicBase, gPanicSize);
723 }
724 }
725
726 static void
727 pe_prepare_images(void)
728 {
729 if ((1 & PE_state.video.v_rotate) != 0) {
730 // Only square square images with radial symmetry are supported
731 // No need to actually rotate the data
732
733 // Swap the dx and dy offsets
734 uint32_t tmp = default_progress.dx;
735 default_progress.dx = default_progress.dy;
736 default_progress.dy = tmp;
737 }
738 #if 0
739 uint32_t cnt, cnt2, cnt3, cnt4;
740 uint32_t tmp, width, height;
741 uint8_t data, *new_data;
742 const uint8_t *old_data;
743
744 width = default_progress.width;
745 height = default_progress.height * default_progress.count;
746
747 // Scale images if the UI is being scaled
748 if (PE_state.video.v_scale > 1) {
749 new_data = kalloc(width * height * scale * scale);
750 if (new_data != 0) {
751 old_data = default_progress_data;
752 default_progress_data = new_data;
753 for (cnt = 0; cnt < height; cnt++) {
754 for (cnt2 = 0; cnt2 < width; cnt2++) {
755 data = *(old_data++);
756 for (cnt3 = 0; cnt3 < scale; cnt3++) {
757 for (cnt4 = 0; cnt4 < scale; cnt4++) {
758 new_data[width * scale * cnt3 + cnt4] = data;
759 }
760 }
761 new_data += scale;
762 }
763 new_data += width * scale * (scale - 1);
764 }
765 default_progress.width *= scale;
766 default_progress.height *= scale;
767 default_progress.dx *= scale;
768 default_progress.dy *= scale;
769 }
770 }
771 #endif
772 }
773
774 void
775 PE_mark_hwaccess(uint64_t thread)
776 {
777 last_hwaccess_thread = thread;
778 asm volatile ("dmb ish");
779 }