2 * Copyright (c) 2000-2017 Apple Inc. All rights reserved.
4 * arm platform expert initialization.
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>
21 #include <pexpert/arm/board_config.h>
22 #elif defined __arm64__
23 #include <pexpert/arm64/board_config.h>
27 /* extern references */
28 extern void pe_identify_machine(boot_args
*bootArgs
);
30 /* static references */
31 static void pe_prepare_images(void);
34 SECURITY_READ_ONLY_LATE(PE_state_t
) PE_state
;
35 #define FW_VERS_LEN 128
36 char firmware_version
[FW_VERS_LEN
];
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.
44 * See osfmk/arm/arm_vm_init.c for more information.
46 SECURITY_READ_ONLY_SPECIAL_SECTION(volatile uint32_t, "__TEXT,__const") debug_enabled
= FALSE
;
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];
55 /* Clock Frequency Info */
56 clock_frequency_info_t gPEClockFrequencyInfo
;
58 vm_offset_t gPanicBase
= 0;
59 unsigned int gPanicSize
;
60 struct embedded_panic_header
*panic_info
= NULL
;
62 #if (DEVELOPMENT || DEBUG) && defined(XNU_TARGET_OS_BRIDGE)
64 * On DEVELOPMENT bridgeOS, we map the x86 panic region
65 * so we can include this data in bridgeOS corefiles
67 uint64_t macos_panic_base
= 0;
68 unsigned int macos_panic_size
= 0;
70 struct macos_panic_header
*mac_panic_header
= NULL
;
73 /* Maximum size of panic log excluding headers, in bytes */
74 static unsigned int panic_text_len
;
76 /* Whether a console is standing by for panic logging */
77 static boolean_t panic_console_available
= FALSE
;
79 extern uint32_t crc32(uint32_t crc
, const void *buf
, size_t size
);
81 void PE_slide_devicetree(vm_offset_t
);
84 check_for_panic_log(void)
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
;
91 DTEntry entry
, chosen
;
93 uintptr_t const *reg_prop
;
94 uint32_t const *panic_region_length
;
97 * DT properties for the panic region are populated by UpdateDeviceTree() in iBoot:
100 * embedded-panic-log-size = <0x00080000>;
101 * [a bunch of other stuff]
105 * reg = <0x00000008_fbc48000 0x00000000_000b4000>;
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
112 if (kSuccess
!= SecureDTLookupEntry(0, "pram", &entry
)) {
116 if (kSuccess
!= SecureDTGetProperty(entry
, "reg", (void const **)®_prop
, &size
)) {
120 if (kSuccess
!= SecureDTLookupEntry(0, "/chosen", &chosen
)) {
124 if (kSuccess
!= SecureDTGetProperty(chosen
, "embedded-panic-log-size", (void const **) &panic_region_length
, &size
)) {
128 gPanicBase
= ml_io_map_wcomb(reg_prop
[0], panic_region_length
[0]);
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];
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
;
145 #endif /* DEVELOPMENT && defined(XNU_TARGET_OS_BRIDGE) */
148 panic_info
= (struct embedded_panic_header
*)gPanicBase
;
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
;
156 /* Check if there's a boot profile in the panic buffer */
157 if (panic_info
->eph_magic
== 'BTRC') {
162 * Check to see if a panic (FUNK) is in VRAM from the last time
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");
168 /* Clear panic region */
169 bzero((void *)gPanicBase
, gPanicSize
);
173 PE_initialize_console(PE_Video
* info
, int op
)
175 static int last_console
= -1;
177 if (info
&& (info
!= &PE_state
.video
)) {
178 info
->v_scale
= PE_state
.video
.v_scale
;
182 case kPEDisableScreen
:
183 initialize_screen(info
, op
);
184 last_console
= switch_to_serial_console();
185 kprintf("kPEDisableScreen %d\n", last_console
);
188 case kPEEnableScreen
:
189 initialize_screen(info
, op
);
191 PE_state
.video
= *info
;
193 kprintf("kPEEnableScreen %d\n", last_console
);
194 if (last_console
!= -1) {
195 switch_to_old_console(last_console
);
199 case kPEReleaseScreen
:
201 * we don't show the progress indicator on boot, but want to
202 * show it afterwards.
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
;
214 initialize_screen(info
, op
);
218 initialize_screen(info
, op
);
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;
239 PE_init_printf(TRUE
);
241 printf("iBoot version: %s\n", firmware_version
);
243 if (kSuccess
== SecureDTLookupEntry(0, "/chosen/memory-map", &entry
)) {
244 boot_progress_element
const *bootPict
;
246 if (kSuccess
== SecureDTGetProperty(entry
, "BootCLUT", (void const **) &map
, &size
)) {
247 bcopy(map
[0], appleClut8
, sizeof(appleClut8
));
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];
262 scale
= PE_state
.video
.v_scale
;
265 #if defined(XNU_TARGET_OS_OSX)
267 show_progress
= TRUE
;
268 if (PE_parse_boot_argn("-restore", ¬used
, sizeof(notused
))) {
269 show_progress
= FALSE
;
271 if (PE_parse_boot_argn("-noprogress", ¬used
, sizeof(notused
))) {
272 show_progress
= FALSE
;
275 show_progress
= FALSE
;
276 PE_parse_boot_argn("-progress", &show_progress
, sizeof(show_progress
));
277 #endif /* XNU_TARGET_OS_OSX */
279 /* Rotation: 0:normal, 1:right 90, 2:left 180, 3:left 90 */
280 switch (PE_state
.video
.v_rotate
) {
285 display_size
= PE_state
.video
.v_height
;
286 image_size
= default_progress
.height
;
287 delta
= &default_progress
.dy
;
294 display_size
= PE_state
.video
.v_width
;
295 image_size
= default_progress
.width
;
296 delta
= &default_progress
.dx
;
299 while (((unsigned)(*delta
+ image_size
)) >= (display_size
/ 2)) {
300 *delta
-= 50 * scale
;
305 /* Check for DT-defined progress y delta */
306 PE_get_default("progress-dy", &default_progress
.dy
, sizeof(default_progress
.dy
));
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
;
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
;
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
;
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
;
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
;
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
;
346 KDBG_RELEASE(IOKDBG_CODE(DBG_BOOTER
, 0), start_time_value
, debug_wait_start_value
, load_kernel_start_value
, populate_registry_time_value
);
349 InitIOKit(PE_state
.deviceTreeHead
);
354 PE_lockdown_iokit(void)
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.
368 StartIOKitMatching();
372 PE_slide_devicetree(vm_offset_t slide
)
374 assert(PE_state
.initialized
);
375 PE_state
.deviceTreeHead
+= slide
;
376 SecureDTInit(PE_state
.deviceTreeHead
, PE_state
.deviceTreeSize
);
380 PE_init_platform(boolean_t vm_initialized
, void *args
)
385 boot_args
*boot_args_ptr
= (boot_args
*) args
;
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
));
402 if (!vm_initialized
) {
404 * Setup the Device Tree routines
405 * so the console can be found and the right I/O space
408 SecureDTInit(PE_state
.deviceTreeHead
, PE_state
.deviceTreeSize
);
409 pe_identify_machine(boot_args_ptr
);
411 pe_arm_init_interrupts(args
);
412 pe_arm_init_debug(args
);
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
);
422 bcopy(prop
, gTargetTypeBuffer
, size
);
423 gTargetTypeBuffer
[size
- 1] = '\0';
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
);
432 bcopy(prop
, gModelTypeBuffer
, size
);
433 gModelTypeBuffer
[size
- 1] = '\0';
436 if (kSuccess
== SecureDTLookupEntry(NULL
, "/chosen", &entry
)) {
437 if (kSuccess
== SecureDTGetProperty(entry
, "debug-enabled",
438 (void const **) &prop
, &size
)) {
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...
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);
451 bcopy(prop
, modify_debug_enabled
, size
);
452 #pragma clang diagnostic pop
454 if (kSuccess
== SecureDTGetProperty(entry
, "firmware-version",
455 (void const **) &prop
, &size
)) {
456 if (size
> sizeof(firmware_version
)) {
457 size
= sizeof(firmware_version
);
459 bcopy(prop
, firmware_version
, size
);
460 firmware_version
[size
- 1] = '\0';
462 if (kSuccess
== SecureDTGetProperty(entry
, "unique-chip-id",
463 (void const **) &prop
, &size
)) {
464 if (size
> sizeof(gPlatformECID
)) {
465 size
= sizeof(gPlatformECID
);
467 bcopy(prop
, gPlatformECID
, size
);
469 if (kSuccess
== SecureDTGetProperty(entry
, "dram-vendor-id",
470 (void const **) &prop
, &size
)) {
471 if (size
> sizeof(gPlatformMemoryID
)) {
472 size
= sizeof(gPlatformMemoryID
);
474 bcopy(prop
, &gPlatformMemoryID
, size
);
482 PE_create_console(void)
485 * Check the head of VRAM for a panic log saved on last panic.
486 * Do this before the VRAM is trashed.
488 check_for_panic_log();
490 if (PE_state
.video
.v_display
) {
491 PE_initialize_console(&PE_state
.video
, kPEGraphicsMode
);
493 PE_initialize_console(&PE_state
.video
, kPETextMode
);
498 PE_current_console(PE_Video
* info
)
500 *info
= PE_state
.video
;
505 PE_display_icon(__unused
unsigned int flags
, __unused
const char *name
)
507 if (default_noroot_data
) {
508 vc_display_icon(&default_noroot
, default_noroot_data
);
513 PE_get_hotkey(__unused
unsigned char key
)
518 static timebase_callback_func gTimebaseCallback
;
521 PE_register_timebase_callback(timebase_callback_func callback
)
523 gTimebaseCallback
= callback
;
525 PE_call_timebase_callback();
529 PE_call_timebase_callback(void)
531 struct timebase_freq_t timebase_freq
;
533 timebase_freq
.timebase_num
= gPEClockFrequencyInfo
.timebase_frequency_hz
;
534 timebase_freq
.timebase_den
= 1;
536 if (gTimebaseCallback
) {
537 gTimebaseCallback(&timebase_freq
);
542 * The default PE_poll_input handler.
545 PE_stub_poll_input(__unused
unsigned int options
, char *c
)
547 *c
= (char)uart_getc();
548 return 0; /* 0 for success, 1 for unsupported */
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).
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.
560 PE_i_can_has_debugger(uint32_t *debug_flags
)
563 #if DEVELOPMENT || DEBUG
564 assert(startup_phase
>= STARTUP_SUB_TUNABLES
);
567 *debug_flags
= debug_boot_arg
;
572 return debug_enabled
;
576 * This routine returns TRUE if the device is configured
577 * with panic debugging enabled.
580 PE_panic_debugging_enabled()
582 return panicDebugging
;
586 PE_save_buffer_to_vram(unsigned char *buf
, unsigned int *size
)
588 if (!panic_info
|| !size
) {
593 *size
= panic_text_len
;
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
);
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
)));
612 PE_get_offset_into_panic_region(char *location
)
614 assert(gPanicBase
!= 0);
615 assert(location
>= (char *) gPanicBase
);
616 assert((unsigned int)(location
- gPanicBase
) < gPanicSize
);
618 return (uint32_t)(uintptr_t)(location
- gPanicBase
);
622 PE_init_panicheader()
628 bzero(panic_info
, sizeof(struct embedded_panic_header
));
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.
634 panic_info
->eph_panic_log_offset
= debug_buf_base
? PE_get_offset_into_panic_region(debug_buf_base
) : 0;
636 panic_info
->eph_magic
= EMBEDDED_PANIC_MAGIC
;
637 panic_info
->eph_version
= EMBEDDED_PANIC_HEADER_CURRENT_VERSION
;
643 * Tries to update the panic header to keep it consistent on nested panics.
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.
649 PE_update_panicheader_nestedpanic()
656 * If the panic log offset is not set, re-init the panic header
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
;
664 panic_info
->eph_panic_flags
|= EMBEDDED_PANIC_HEADER_FLAG_NESTED_PANIC
;
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.
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
);
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);
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)));
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
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
);
688 /* If this assert fires, it's indicative of corruption in the panic region */
689 assert(panic_info
->eph_other_log_len
== 0);
696 PE_reboot_on_panic(void)
698 uint32_t debug_flags
;
700 if (PE_i_can_has_debugger(&debug_flags
)
701 && (debug_flags
& DB_NMI
)) {
702 /* kernel debugging is active */
710 PE_sync_panic_buffers(void)
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.
722 CleanPoC_DcacheRegion_Force(gPanicBase
, gPanicSize
);
727 pe_prepare_images(void)
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
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
;
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
;
744 width
= default_progress
.width
;
745 height
= default_progress
.height
* default_progress
.count
;
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
);
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
;
763 new_data
+= width
* scale
* (scale
- 1);
765 default_progress
.width
*= scale
;
766 default_progress
.height
*= scale
;
767 default_progress
.dx
*= scale
;
768 default_progress
.dy
*= scale
;
775 PE_mark_hwaccess(uint64_t thread
)
777 last_hwaccess_thread
= thread
;
778 asm volatile ("dmb ish");