]> git.saurik.com Git - apple/xnu.git/blame - iokit/Kernel/IOHibernateRestoreKernel.c
xnu-7195.50.7.100.1.tar.gz
[apple/xnu.git] / iokit / Kernel / IOHibernateRestoreKernel.c
CommitLineData
3a60a9f5 1/*
2d21ac55 2 * Copyright (c) 2004-2006 Apple Computer, Inc. All rights reserved.
3a60a9f5 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
0a7de745 5 *
2d21ac55
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
0a7de745 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
0a7de745 17 *
2d21ac55
A
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
0a7de745 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
3a60a9f5
A
27 */
28
29#include <stdint.h>
f427ee49 30#include <sys/param.h>
3a60a9f5
A
31#include <mach/mach_types.h>
32#include <mach/vm_param.h>
33#include <IOKit/IOHibernatePrivate.h>
0c530ab8 34#include <IOKit/IOLib.h>
3a60a9f5 35#include <pexpert/boot.h>
2d21ac55 36#include <libkern/libkern.h>
3a60a9f5 37
3a60a9f5
A
38#include "IOHibernateInternal.h"
39
bd504ef0 40#include <machine/pal_hibernate.h>
6d2010ae 41
3a60a9f5 42/*
0a7de745
A
43 * This code is linked into the kernel but part of the "__HIB" section, which means
44 * its used by code running in the special context of restoring the kernel text and data
45 * from the hibernation image read by the booter. hibernate_kernel_entrypoint() and everything
46 * it calls or references needs to be careful to only touch memory also in the "__HIB" section.
47 */
3a60a9f5 48
f427ee49
A
49#define HIB_ROUND_PAGE(x) (((x) + PAGE_MASK) & ~PAGE_MASK)
50
3a60a9f5
A
51uint32_t gIOHibernateState;
52
b0d623f7
A
53uint32_t gIOHibernateDebugFlags;
54
3a60a9f5
A
55static IOHibernateImageHeader _hibernateHeader;
56IOHibernateImageHeader * gIOHibernateCurrentHeader = &_hibernateHeader;
57
6d2010ae 58ppnum_t gIOHibernateHandoffPages[64];
f427ee49 59const uint32_t gIOHibernateHandoffPageCount = sizeof(gIOHibernateHandoffPages)
0a7de745 60 / sizeof(gIOHibernateHandoffPages[0]);
3a60a9f5 61
6d2010ae
A
62#if CONFIG_DEBUG
63void hibprintf(const char *fmt, ...);
64#else
65#define hibprintf(x...)
66#endif
0c530ab8 67
b0d623f7
A
68
69#if CONFIG_SLEEP
70#if defined(__i386__) || defined(__x86_64__)
71extern void acpi_wake_prot_entry(void);
72#endif
73#endif
74
75/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
76
77#if defined(__i386__) || defined(__x86_64__)
5ba3f43e 78#include <i386/proc_reg.h>
bd504ef0
A
79#else
80
0a7de745
A
81static inline uint64_t
82rdtsc64(void)
bd504ef0 83{
0a7de745 84 return 0;
bd504ef0
A
85}
86
87#endif /* defined(__i386__) || defined(__x86_64__) */
88
89#if defined(__i386__) || defined(__x86_64__)
90
0a7de745 91#define DBGLOG 1
b0d623f7
A
92
93#include <architecture/i386/pio.h>
94
95/* standard port addresses */
96enum {
0a7de745
A
97 COM1_PORT_ADDR = 0x3f8,
98 COM2_PORT_ADDR = 0x2f8
b0d623f7
A
99};
100
101/* UART register offsets */
102enum {
0a7de745
A
103 UART_RBR = 0, /* receive buffer Register (R) */
104 UART_THR = 0, /* transmit holding register (W) */
105 UART_DLL = 0, /* DLAB = 1, divisor latch (LSB) */
106 UART_IER = 1, /* interrupt enable register */
107 UART_DLM = 1, /* DLAB = 1, divisor latch (MSB) */
108 UART_IIR = 2, /* interrupt ident register (R) */
109 UART_FCR = 2, /* fifo control register (W) */
110 UART_LCR = 3, /* line control register */
111 UART_MCR = 4, /* modem control register */
112 UART_LSR = 5, /* line status register */
113 UART_MSR = 6, /* modem status register */
114 UART_SCR = 7 /* scratch register */
b0d623f7
A
115};
116
117enum {
0a7de745
A
118 UART_LCR_8BITS = 0x03,
119 UART_LCR_DLAB = 0x80
b0d623f7
A
120};
121
122enum {
0a7de745
A
123 UART_MCR_DTR = 0x01,
124 UART_MCR_RTS = 0x02,
125 UART_MCR_OUT1 = 0x04,
126 UART_MCR_OUT2 = 0x08,
127 UART_MCR_LOOP = 0x10
b0d623f7
A
128};
129
130enum {
0a7de745
A
131 UART_LSR_DR = 0x01,
132 UART_LSR_OE = 0x02,
133 UART_LSR_PE = 0x04,
134 UART_LSR_FE = 0x08,
135 UART_LSR_THRE = 0x20
b0d623f7
A
136};
137
0a7de745 138static void
f427ee49 139hib_uart_putc(char c)
b0d623f7 140{
0a7de745
A
141 while (!(inb(COM1_PORT_ADDR + UART_LSR) & UART_LSR_THRE)) {
142 }
143 outb(COM1_PORT_ADDR + UART_THR, c);
b0d623f7
A
144}
145
0a7de745
A
146static int
147debug_probe( void )
b0d623f7 148{
0a7de745
A
149 /* Verify that the Scratch Register is accessible */
150 outb(COM1_PORT_ADDR + UART_SCR, 0x5a);
151 if (inb(COM1_PORT_ADDR + UART_SCR) != 0x5a) {
152 return false;
153 }
154 outb(COM1_PORT_ADDR + UART_SCR, 0xa5);
155 if (inb(COM1_PORT_ADDR + UART_SCR) != 0xa5) {
156 return false;
157 }
f427ee49 158 hib_uart_putc('\n');
0a7de745 159 return true;
b0d623f7
A
160}
161
f427ee49
A
162#elif defined(__arm64__)
163
164#define DBGLOG 1
165
166#include <pexpert/arm/dockchannel.h>
167#include <pexpert/arm/S3cUART.h>
168#define dockchannel_uart_base gHibernateGlobals.dockChannelRegBase
169#define uart_base gHibernateGlobals.hibUartRegBase
170
171static void
172hib_uart_putc(char c)
173{
174 if (dockchannel_uart_base) {
175 while ((rDOCKCHANNELS_DEV_WSTAT(DOCKCHANNEL_UART_CHANNEL) & gHibernateGlobals.dockChannelWstatMask) == 0) {
176 }
177 rDOCKCHANNELS_DEV_WDATA1(DOCKCHANNEL_UART_CHANNEL) = c;
178 }
179 if (uart_base) {
180 while ((rUTRSTAT0 & 0x04) == 0) {
181 // wait for space in the uart
182 }
183 rUTXH0 = c;
184 }
185}
186
187static int
188debug_probe( void )
189{
190 // todo
191 return false;
192}
193
194#endif /* defined(__arm64__) */
195
196#if defined(__i386__) || defined(__x86_64__) || defined(__arm64__)
197
198static void
199uart_putstring(const char *str)
200{
201 while (*str) {
202 hib_uart_putc(*str++);
203 }
204}
205
206static void
207uart_putdec(uint64_t num)
208{
209 bool leading = true;
210 for (uint64_t pos = 10000000000000000000ull; pos != 0; pos /= 10) {
211 char c = (char) (num / pos);
212 if (c) {
213 leading = false;
214 num -= c * pos;
215 } else if (leading && (pos != 1)) {
216 continue;
217 }
218 hib_uart_putc(c + '0');
219 }
220}
221
0a7de745
A
222static void
223uart_puthex(uint64_t num)
b0d623f7 224{
0a7de745
A
225 int bit;
226 char c;
227 bool leading = true;
228
229 for (bit = 60; bit >= 0; bit -= 4) {
230 c = 0xf & (num >> bit);
231 if (c) {
232 leading = false;
233 } else if (leading && bit) {
234 continue;
235 }
236 if (c <= 9) {
237 c += '0';
238 } else {
239 c += 'a' - 10;
240 }
f427ee49 241 hib_uart_putc(c);
0a7de745 242 }
b0d623f7
A
243}
244
0a7de745
A
245static void
246debug_code(uint32_t code, uint64_t value)
b0d623f7 247{
0a7de745
A
248 int bit;
249 char c;
250
251 if (!(kIOHibernateDebugRestoreLogs & gIOHibernateDebugFlags)) {
252 return;
253 }
254
255 for (bit = 24; bit >= 0; bit -= 8) {
256 c = 0xFF & (code >> bit);
257 if (c) {
f427ee49 258 hib_uart_putc(c);
0a7de745
A
259 }
260 }
f427ee49 261 hib_uart_putc('=');
0a7de745 262 uart_puthex(value);
f427ee49
A
263 hib_uart_putc('\n');
264 hib_uart_putc('\r');
b0d623f7
A
265}
266
f427ee49 267#endif /* defined(__i386__) || defined(__x86_64__) || defined(__arm64__) */
b0d623f7
A
268
269#if !defined(DBGLOG)
0a7de745 270#define debug_probe() (false)
b0d623f7 271#define debug_code(c, v) {}
3a60a9f5
A
272#endif
273
0a7de745
A
274enum{
275 kIOHibernateRestoreCodeImageStart = 'imgS',
276 kIOHibernateRestoreCodeImageEnd = 'imgE',
277 kIOHibernateRestoreCodePageIndexStart = 'pgiS',
278 kIOHibernateRestoreCodePageIndexEnd = 'pgiE',
279 kIOHibernateRestoreCodeMapStart = 'mapS',
280 kIOHibernateRestoreCodeMapEnd = 'mapE',
281 kIOHibernateRestoreCodeWakeMapSize = 'wkms',
282 kIOHibernateRestoreCodeConflictPage = 'cfpg',
283 kIOHibernateRestoreCodeConflictSource = 'cfsr',
284 kIOHibernateRestoreCodeNoMemory = 'nomm',
285 kIOHibernateRestoreCodeTag = 'tag ',
286 kIOHibernateRestoreCodeSignature = 'sign',
287 kIOHibernateRestoreCodeMapVirt = 'mapV',
288 kIOHibernateRestoreCodeHandoffPages = 'hand',
289 kIOHibernateRestoreCodeHandoffCount = 'hndc',
b0d623f7
A
290};
291
292/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
293
294
f427ee49
A
295void
296__hib_assert(const char *file, int line, const char *expression)
b0d623f7 297{
f427ee49
A
298 uart_putstring(file);
299 hib_uart_putc(':');
300 uart_putdec(line);
301 uart_putstring(" Assertion failed: ");
302 uart_putstring(expression);
303 hib_uart_putc('\n');
b0d623f7 304#if defined(__i386__) || defined(__x86_64__)
0a7de745 305 outb(0xcf9, 6);
f427ee49 306#endif /* defined(__i386__) || defined(__x86_64__) */
0a7de745
A
307 while (true) {
308 }
b0d623f7
A
309}
310
3a60a9f5
A
311/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
312
3a60a9f5 313uint32_t
0b4c1975 314hibernate_sum_page(uint8_t *buf, uint32_t ppnum)
3a60a9f5 315{
0a7de745 316 return ((uint32_t *)buf)[((PAGE_SIZE >> 2) - 1) & ppnum];
3a60a9f5
A
317}
318
319/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
320
0c530ab8
A
321static hibernate_bitmap_t *
322hibernate_page_bitmap(hibernate_page_list_t * list, uint32_t page)
89b3af67 323{
0a7de745
A
324 uint32_t bank;
325 hibernate_bitmap_t * bitmap = &list->bank_bitmap[0];
326
327 for (bank = 0; bank < list->bank_count; bank++) {
328 if ((page >= bitmap->first_page) && (page <= bitmap->last_page)) {
329 break;
330 }
331 bitmap = (hibernate_bitmap_t *) &bitmap->bitmap[bitmap->bitmapwords];
332 }
333 if (bank == list->bank_count) {
334 bitmap = NULL;
335 }
336
337 return bitmap;
4452a7af
A
338}
339
0c530ab8
A
340hibernate_bitmap_t *
341hibernate_page_bitmap_pin(hibernate_page_list_t * list, uint32_t * pPage)
4452a7af 342{
0a7de745
A
343 uint32_t bank, page = *pPage;
344 hibernate_bitmap_t * bitmap = &list->bank_bitmap[0];
345
346 for (bank = 0; bank < list->bank_count; bank++) {
347 if (page <= bitmap->first_page) {
348 *pPage = bitmap->first_page;
349 break;
350 }
351 if (page <= bitmap->last_page) {
352 break;
353 }
354 bitmap = (hibernate_bitmap_t *) &bitmap->bitmap[bitmap->bitmapwords];
6601e61a 355 }
0a7de745
A
356 if (bank == list->bank_count) {
357 bitmap = NULL;
358 }
359
360 return bitmap;
0c530ab8
A
361}
362
0a7de745 363void
0c530ab8
A
364hibernate_page_bitset(hibernate_page_list_t * list, boolean_t set, uint32_t page)
365{
0a7de745
A
366 hibernate_bitmap_t * bitmap;
367
368 bitmap = hibernate_page_bitmap(list, page);
369 if (bitmap) {
370 page -= bitmap->first_page;
371 if (set) {
372 bitmap->bitmap[page >> 5] |= (0x80000000 >> (page & 31));
373 }
374 //setbit(page - bitmap->first_page, (int *) &bitmap->bitmap[0]);
375 else {
376 bitmap->bitmap[page >> 5] &= ~(0x80000000 >> (page & 31));
377 }
378 //clrbit(page - bitmap->first_page, (int *) &bitmap->bitmap[0]);
379 }
0c530ab8
A
380}
381
0a7de745 382boolean_t
0c530ab8
A
383hibernate_page_bittst(hibernate_page_list_t * list, uint32_t page)
384{
0a7de745
A
385 boolean_t result = TRUE;
386 hibernate_bitmap_t * bitmap;
387
388 bitmap = hibernate_page_bitmap(list, page);
389 if (bitmap) {
390 page -= bitmap->first_page;
391 result = (0 != (bitmap->bitmap[page >> 5] & (0x80000000 >> (page & 31))));
392 }
393 return result;
3a60a9f5
A
394}
395
0c530ab8 396// count bits clear or set (set == TRUE) starting at page.
3a60a9f5 397uint32_t
0c530ab8 398hibernate_page_bitmap_count(hibernate_bitmap_t * bitmap, uint32_t set, uint32_t page)
3a60a9f5 399{
0a7de745
A
400 uint32_t index, bit, bits;
401 uint32_t count;
402
403 count = 0;
404
405 index = (page - bitmap->first_page) >> 5;
406 bit = (page - bitmap->first_page) & 31;
407
408 bits = bitmap->bitmap[index];
409 if (set) {
0c530ab8 410 bits = ~bits;
0a7de745
A
411 }
412 bits = (bits << bit);
413 if (bits) {
0c530ab8 414 count += __builtin_clz(bits);
0a7de745
A
415 } else {
416 count += 32 - bit;
417 while (++index < bitmap->bitmapwords) {
418 bits = bitmap->bitmap[index];
419 if (set) {
420 bits = ~bits;
421 }
422 if (bits) {
423 count += __builtin_clz(bits);
424 break;
425 }
426 count += 32;
427 }
3a60a9f5 428 }
3a60a9f5 429
0a7de745
A
430 if ((page + count) > (bitmap->last_page + 1)) {
431 count = (bitmap->last_page + 1) - page;
432 }
7ddcb079 433
0a7de745 434 return count;
3a60a9f5
A
435}
436
f427ee49 437ppnum_t
0c530ab8 438hibernate_page_list_grab(hibernate_page_list_t * list, uint32_t * pNextFree)
3a60a9f5 439{
0a7de745
A
440 uint32_t nextFree = *pNextFree;
441 uint32_t nextFreeInBank;
442 hibernate_bitmap_t * bitmap;
443
444 nextFreeInBank = nextFree + 1;
445 while ((bitmap = hibernate_page_bitmap_pin(list, &nextFreeInBank))) {
446 nextFreeInBank += hibernate_page_bitmap_count(bitmap, FALSE, nextFreeInBank);
447 if (nextFreeInBank <= bitmap->last_page) {
448 *pNextFree = nextFreeInBank;
449 break;
450 }
0c530ab8 451 }
3a60a9f5 452
0a7de745
A
453 if (!bitmap) {
454 debug_code(kIOHibernateRestoreCodeNoMemory, nextFree);
f427ee49 455 HIB_ASSERT(0);
0a7de745 456 }
b0d623f7 457
0a7de745 458 return nextFree;
3a60a9f5
A
459}
460
f427ee49
A
461#pragma mark -
462#pragma mark hibernate_scratch
463
464void
465hibernate_scratch_init(hibernate_scratch_t * scratch, hibernate_page_list_t * map, uint32_t * nextFree)
466{
467 // initialize "scratch" so we can start writing into it
468 __nosan_bzero(scratch, sizeof(*scratch));
469 scratch->map = map;
470 scratch->nextFree = nextFree;
471 scratch->headPage = hibernate_page_list_grab(scratch->map, scratch->nextFree);
472 scratch->curPage = (uint8_t *)pal_hib_map(SCRATCH_AREA, ptoa_64(scratch->headPage));
473}
474
475void
476hibernate_scratch_start_read(hibernate_scratch_t * scratch)
477{
478 // re-initialize "scratch" so we can start reading from it it
479 hibernate_scratch_t result;
480 __nosan_bzero(&result, sizeof(result));
481 result.headPage = scratch->headPage;
482 result.curPage = (uint8_t *)pal_hib_map(SCRATCH_AREA, ptoa_64(result.headPage));
483 result.totalLength = scratch->curPos;
484 *scratch = result;
485}
486
487static void
488hibernate_scratch_io(hibernate_scratch_t * scratch, void * buffer, size_t size, bool write)
489{
490 // copy data to or from "scratch" based on the value of "write"
491 if (!write) {
492 // check that we are in bounds
493 HIB_ASSERT(scratch->curPos + size <= scratch->totalLength);
494 }
495 while (size) {
496 // if we got to the end of a page (leaving room for our chain pointer), advance to the next page
497 if (scratch->curPagePos == PAGE_SIZE - sizeof(ppnum_t)) {
498 ppnum_t *nextPage = (ppnum_t *)(scratch->curPage + scratch->curPagePos);
499 if (write) {
500 // allocate the next page and store the page number
501 *nextPage = hibernate_page_list_grab(scratch->map, scratch->nextFree);
502 }
503 scratch->curPage = (uint8_t *)pal_hib_map(SCRATCH_AREA, ptoa_64(*nextPage));
504 scratch->curPagePos = 0;
505 }
506 size_t curPageRemaining = PAGE_SIZE - sizeof(ppnum_t) - scratch->curPagePos;
507 size_t toCopy = MIN(size, curPageRemaining);
508 if (write) {
509 // copy from "buffer" into "scratch"
510 __nosan_memcpy(scratch->curPage + scratch->curPagePos, buffer, toCopy);
511 } else {
512 // copy from "scratch" into "buffer"
513 __nosan_memcpy(buffer, scratch->curPage + scratch->curPagePos, toCopy);
514 }
515 scratch->curPos += toCopy;
516 scratch->curPagePos += toCopy;
517 buffer += toCopy;
518 size -= toCopy;
519 }
520}
521
522void
523hibernate_scratch_write(hibernate_scratch_t * scratch, const void * buffer, size_t size)
524{
525 hibernate_scratch_io(scratch, (void *)(uintptr_t)buffer, size, true);
526}
527
528void
529hibernate_scratch_read(hibernate_scratch_t * scratch, void * buffer, size_t size)
530{
531 hibernate_scratch_io(scratch, buffer, size, false);
532}
533
534#pragma mark -
535
3a60a9f5 536static uint32_t
0a7de745 537store_one_page(uint32_t procFlags, uint32_t * src, uint32_t compressedSize,
f427ee49 538 uint8_t * scratch, uint32_t ppnum)
3a60a9f5 539{
6d2010ae 540 uint64_t dst = ptoa_64(ppnum);
3a60a9f5 541
0a7de745 542 if (compressedSize != PAGE_SIZE) {
6d2010ae 543 dst = pal_hib_map(DEST_COPY_AREA, dst);
0a7de745 544 if (compressedSize != 4) {
f427ee49 545 pal_hib_decompress_page(src, (void *)dst, scratch, compressedSize);
0a7de745 546 } else {
743345f9
A
547 size_t i;
548 uint32_t s, *d;
3e170ce0 549
743345f9
A
550 s = *src;
551 d = (uint32_t *)(uintptr_t)dst;
0a7de745
A
552 if (!s) {
553 __nosan_bzero((void *) dst, PAGE_SIZE);
554 } else {
555 for (i = 0; i < (PAGE_SIZE / sizeof(int32_t)); i++) {
556 *d++ = s;
557 }
558 }
3e170ce0 559 }
0a7de745 560 } else {
6d2010ae
A
561 dst = hibernate_restore_phys_page((uint64_t) (uintptr_t) src, dst, PAGE_SIZE, procFlags);
562 }
3a60a9f5 563
6d2010ae 564 return hibernate_sum_page((uint8_t *)(uintptr_t)dst, ppnum);
3a60a9f5
A
565}
566
f427ee49
A
567void
568hibernate_reserve_restore_pages(uint64_t headerPhys, IOHibernateImageHeader *header, hibernate_page_list_t * map)
569{
570 uint32_t lastImagePage = atop_64_ppnum(HIB_ROUND_PAGE(headerPhys + header->image1Size));
571 uint32_t handoffPages = header->handoffPages;
572 uint32_t handoffPageCount = header->handoffPageCount;
573 uint32_t ppnum;
574
575 // knock all the image pages to be used out of free map
576 for (ppnum = atop_64_ppnum(headerPhys); ppnum <= lastImagePage; ppnum++) {
577 hibernate_page_bitset(map, FALSE, ppnum);
578 }
579 // knock all the handoff pages to be used out of free map
580 for (ppnum = handoffPages; ppnum < (handoffPages + handoffPageCount); ppnum++) {
581 hibernate_page_bitset(map, FALSE, ppnum);
582 }
583}
584
0a7de745
A
585long
586hibernate_kernel_entrypoint(uint32_t p1,
587 uint32_t p2, uint32_t p3, uint32_t p4)
3a60a9f5 588{
0a7de745
A
589 uint64_t headerPhys;
590 uint64_t mapPhys;
591 uint64_t srcPhys;
592 uint64_t imageReadPhys;
593 uint64_t pageIndexPhys;
594 uint32_t * pageIndexSource;
595 hibernate_page_list_t * map;
f427ee49 596 pal_hib_restore_stage_t stage;
0a7de745
A
597 uint32_t count;
598 uint32_t ppnum;
599 uint32_t page;
600 uint32_t conflictCount;
601 uint32_t compressedSize;
602 uint32_t uncompressedPages;
0a7de745 603 uint32_t * src;
0a7de745
A
604 uint32_t sum;
605 uint32_t pageSum;
606 uint32_t nextFree;
607 uint32_t lastImagePage;
608 uint32_t lastMapPage;
609 uint32_t lastPageIndexPage;
610 uint32_t handoffPages;
611 uint32_t handoffPageCount;
f427ee49
A
612 uint8_t * wkdmScratch;
613 hibernate_scratch_t conflictList;
614 pal_hib_ctx_t palHibCtx;
0a7de745
A
615
616 uint64_t timeStart;
617 timeStart = rdtsc64();
618
f427ee49 619#if !defined(__arm64__)
0a7de745 620 static_assert(sizeof(IOHibernateImageHeader) == 512);
f427ee49 621#endif /* !defined(__arm64__) */
0a7de745
A
622
623 headerPhys = ptoa_64(p1);
624
625 if ((kIOHibernateDebugRestoreLogs & gIOHibernateDebugFlags) && !debug_probe()) {
626 gIOHibernateDebugFlags &= ~kIOHibernateDebugRestoreLogs;
6d2010ae
A
627 }
628
0a7de745
A
629 debug_code(kIOHibernateRestoreCodeImageStart, headerPhys);
630
631 __nosan_memcpy(gIOHibernateCurrentHeader,
632 (void *) pal_hib_map(IMAGE_AREA, headerPhys),
633 sizeof(IOHibernateImageHeader));
634
635 debug_code(kIOHibernateRestoreCodeSignature, gIOHibernateCurrentHeader->signature);
636
637 mapPhys = headerPhys
638 + (offsetof(IOHibernateImageHeader, fileExtentMap)
639 + gIOHibernateCurrentHeader->fileExtentMapSize
640 + ptoa_32(gIOHibernateCurrentHeader->restore1PageCount)
641 + gIOHibernateCurrentHeader->previewSize);
642
643 map = (hibernate_page_list_t *) pal_hib_map(BITMAP_AREA, mapPhys);
644
f427ee49
A
645
646 // make the rest of the image is safe for atop()
647 uint64_t imageEnd;
648 if (os_add_overflow(headerPhys, gIOHibernateCurrentHeader->image1Size, &imageEnd) || (imageEnd > IO_MAX_PAGE_ADDR)) {
649 HIB_ASSERT(0);
650 }
651
652 lastImagePage = atop_64_ppnum(HIB_ROUND_PAGE(headerPhys + gIOHibernateCurrentHeader->image1Size));
653 lastMapPage = atop_64_ppnum(HIB_ROUND_PAGE(mapPhys + gIOHibernateCurrentHeader->bitmapSize));
0a7de745
A
654
655 handoffPages = gIOHibernateCurrentHeader->handoffPages;
656 handoffPageCount = gIOHibernateCurrentHeader->handoffPageCount;
657
658 debug_code(kIOHibernateRestoreCodeImageEnd, ptoa_64(lastImagePage));
659 debug_code(kIOHibernateRestoreCodeMapStart, mapPhys);
660 debug_code(kIOHibernateRestoreCodeMapEnd, ptoa_64(lastMapPage));
6d2010ae 661
0a7de745
A
662 debug_code(kIOHibernateRestoreCodeMapVirt, (uintptr_t) map);
663 debug_code(kIOHibernateRestoreCodeHandoffPages, ptoa_64(handoffPages));
664 debug_code(kIOHibernateRestoreCodeHandoffCount, handoffPageCount);
665
f427ee49
A
666#if defined(__arm64__)
667 // on arm64 we've already done this in pal_hib_resume_tramp
668#else /* !defined(__arm64__) */
669 hibernate_reserve_restore_pages(headerPhys, gIOHibernateCurrentHeader, map);
670#endif /* !defined(__arm64__) */
0a7de745
A
671
672 nextFree = 0;
673 hibernate_page_list_grab(map, &nextFree);
674
f427ee49
A
675 pal_hib_resume_init(&palHibCtx, map, &nextFree);
676
677 // allocate scratch space for wkdm
678 wkdmScratch = (uint8_t *)pal_hib_map(WKDM_AREA, ptoa_64(hibernate_page_list_grab(map, &nextFree)));
679
0a7de745 680 sum = gIOHibernateCurrentHeader->actualRestore1Sum;
f427ee49 681 gIOHibernateCurrentHeader->diag[0] = atop_64_ppnum(headerPhys);
0a7de745
A
682 gIOHibernateCurrentHeader->diag[1] = sum;
683 gIOHibernateCurrentHeader->trampolineTime = 0;
684
685 uncompressedPages = 0;
686 conflictCount = 0;
0a7de745
A
687
688 compressedSize = PAGE_SIZE;
f427ee49 689 stage = pal_hib_restore_stage_handoff_data;
0a7de745
A
690 count = 0;
691 srcPhys = 0;
692
693 if (gIOHibernateCurrentHeader->previewSize) {
694 pageIndexPhys = headerPhys
695 + (offsetof(IOHibernateImageHeader, fileExtentMap)
696 + gIOHibernateCurrentHeader->fileExtentMapSize
697 + ptoa_32(gIOHibernateCurrentHeader->restore1PageCount));
698 imageReadPhys = (pageIndexPhys + gIOHibernateCurrentHeader->previewPageListSize);
f427ee49 699 lastPageIndexPage = atop_64_ppnum(HIB_ROUND_PAGE(imageReadPhys));
0a7de745
A
700 pageIndexSource = (uint32_t *) pal_hib_map(IMAGE2_AREA, pageIndexPhys);
701 } else {
702 pageIndexPhys = 0;
703 lastPageIndexPage = 0;
704 imageReadPhys = (mapPhys + gIOHibernateCurrentHeader->bitmapSize);
3a60a9f5
A
705 }
706
0a7de745
A
707 debug_code(kIOHibernateRestoreCodePageIndexStart, pageIndexPhys);
708 debug_code(kIOHibernateRestoreCodePageIndexEnd, ptoa_64(lastPageIndexPage));
3a60a9f5 709
0a7de745
A
710 while (1) {
711 switch (stage) {
f427ee49 712 case pal_hib_restore_stage_handoff_data:
0a7de745
A
713 // copy handoff data
714 count = srcPhys ? 0 : handoffPageCount;
715 if (!count) {
716 break;
717 }
718 if (count > gIOHibernateHandoffPageCount) {
719 count = gIOHibernateHandoffPageCount;
720 }
721 srcPhys = ptoa_64(handoffPages);
722 break;
7ddcb079 723
f427ee49 724 case pal_hib_restore_stage_preview_pages:
0a7de745
A
725 // copy pageIndexSource pages == preview image data
726 if (!srcPhys) {
727 if (!pageIndexPhys) {
728 break;
729 }
730 srcPhys = imageReadPhys;
731 }
732 ppnum = pageIndexSource[0];
733 count = pageIndexSource[1];
734 pageIndexSource += 2;
735 pageIndexPhys += 2 * sizeof(pageIndexSource[0]);
736 imageReadPhys = srcPhys;
737 break;
738
f427ee49 739 case pal_hib_restore_stage_dram_pages:
0a7de745
A
740 // copy pages
741 if (!srcPhys) {
742 srcPhys = (mapPhys + gIOHibernateCurrentHeader->bitmapSize);
743 }
744 src = (uint32_t *) pal_hib_map(IMAGE_AREA, srcPhys);
745 ppnum = src[0];
746 count = src[1];
747 srcPhys += 2 * sizeof(*src);
748 imageReadPhys = srcPhys;
749 break;
750 }
751
752
753 if (!count) {
f427ee49 754 if (stage == pal_hib_restore_stage_dram_pages) {
0a7de745
A
755 break;
756 }
757 stage--;
758 srcPhys = 0;
759 continue;
760 }
761
762 for (page = 0; page < count; page++, ppnum++) {
763 uint32_t tag;
764 int conflicts;
765
766 src = (uint32_t *) pal_hib_map(IMAGE_AREA, srcPhys);
767
f427ee49 768 if (stage == pal_hib_restore_stage_handoff_data) {
0a7de745 769 ppnum = gIOHibernateHandoffPages[page];
f427ee49 770 } else if (stage == pal_hib_restore_stage_dram_pages) {
0a7de745 771 tag = *src++;
f427ee49 772 HIB_ASSERT((tag & ~kIOHibernateTagLength) == kIOHibernateTagSignature);
7ddcb079 773// debug_code(kIOHibernateRestoreCodeTag, (uintptr_t) tag);
0a7de745
A
774 srcPhys += sizeof(*src);
775 compressedSize = kIOHibernateTagLength & tag;
f427ee49 776 HIB_ASSERT(compressedSize <= PAGE_SIZE);
0a7de745 777 }
6d2010ae 778
f427ee49 779 conflicts = (ppnum >= atop_64_ppnum(mapPhys)) && (ppnum <= lastMapPage);
3a60a9f5 780
f427ee49 781 conflicts |= ((ppnum >= atop_64_ppnum(imageReadPhys)) && (ppnum <= lastImagePage));
3a60a9f5 782
f427ee49
A
783 if (stage >= pal_hib_restore_stage_handoff_data) {
784 conflicts |= ((ppnum >= atop_64_ppnum(srcPhys)) && (ppnum <= (handoffPages + handoffPageCount - 1)));
0a7de745 785 }
6d2010ae 786
f427ee49
A
787 if (stage >= pal_hib_restore_stage_preview_pages) {
788 conflicts |= ((ppnum >= atop_64_ppnum(pageIndexPhys)) && (ppnum <= lastPageIndexPage));
0a7de745 789 }
3a60a9f5 790
0a7de745
A
791 if (!conflicts) {
792 pageSum = store_one_page(gIOHibernateCurrentHeader->processorFlags,
f427ee49
A
793 src, compressedSize, wkdmScratch, ppnum);
794 if (stage != pal_hib_restore_stage_handoff_data) {
0a7de745
A
795 sum += pageSum;
796 }
797 uncompressedPages++;
798 } else {
b0d623f7
A
799// debug_code(kIOHibernateRestoreCodeConflictPage, ppnum);
800// debug_code(kIOHibernateRestoreCodeConflictSource, (uintptr_t) src);
0a7de745 801 conflictCount++;
f427ee49
A
802 if (!conflictList.headPage) {
803 hibernate_scratch_init(&conflictList, map, &nextFree);
0a7de745 804 }
f427ee49
A
805 hibernate_scratch_write(&conflictList, &ppnum, sizeof(ppnum));
806 hibernate_scratch_write(&conflictList, &compressedSize, sizeof(compressedSize));
807 hibernate_scratch_write(&conflictList, &stage, sizeof(stage));
808 hibernate_scratch_write(&conflictList, src, compressedSize);
0a7de745
A
809 }
810 srcPhys += ((compressedSize + 3) & ~3);
811 src += ((compressedSize + 3) >> 2);
f427ee49 812 pal_hib_restored_page(&palHibCtx, stage, ppnum);
3a60a9f5 813 }
3a60a9f5 814 }
0a7de745
A
815
816 /* src points to the last page restored, so we need to skip over that */
f427ee49 817 pal_hib_restore_pal_state(src);
0a7de745
A
818
819 // -- copy back conflicts
820
f427ee49
A
821 if (conflictCount) {
822 src = (uint32_t *)pal_hib_map(COPY_PAGE_AREA, ptoa_64(hibernate_page_list_grab(map, &nextFree)));
823 hibernate_scratch_start_read(&conflictList);
824 for (uint32_t i = 0; i < conflictCount; i++) {
825 hibernate_scratch_read(&conflictList, &ppnum, sizeof(ppnum));
826 hibernate_scratch_read(&conflictList, &compressedSize, sizeof(compressedSize));
827 hibernate_scratch_read(&conflictList, &stage, sizeof(stage));
828 HIB_ASSERT(compressedSize <= PAGE_SIZE);
829 hibernate_scratch_read(&conflictList, src, compressedSize);
0a7de745 830 pageSum = store_one_page(gIOHibernateCurrentHeader->processorFlags,
f427ee49
A
831 src, compressedSize, wkdmScratch, ppnum);
832 if (stage != pal_hib_restore_stage_handoff_data) {
0a7de745
A
833 sum += pageSum;
834 }
835 uncompressedPages++;
836 }
3a60a9f5 837 }
3a60a9f5 838
f427ee49 839 pal_hib_patchup(&palHibCtx);
6d2010ae 840
0a7de745 841 // -- image has been destroyed...
3a60a9f5 842
0a7de745
A
843 gIOHibernateCurrentHeader->actualImage1Sum = sum;
844 gIOHibernateCurrentHeader->actualUncompressedPages = uncompressedPages;
845 gIOHibernateCurrentHeader->conflictCount = conflictCount;
846 gIOHibernateCurrentHeader->nextFree = nextFree;
3a60a9f5 847
0a7de745 848 gIOHibernateState = kIOHibernateStateWakingFromHibernate;
3a60a9f5 849
f427ee49 850 gIOHibernateCurrentHeader->trampolineTime = ((uint32_t) (((rdtsc64() - timeStart)) >> 8));
bd504ef0 851
3e170ce0
A
852// debug_code('done', 0);
853
b0d623f7 854#if CONFIG_SLEEP
6d2010ae 855#if defined(__i386__) || defined(__x86_64__)
0a7de745
A
856 typedef void (*ResetProc)(void);
857 ResetProc proc;
858 proc = HIB_ENTRYPOINT;
859 // flush caches
860 __asm__("wbinvd");
861 proc();
f427ee49
A
862 return -1;
863#elif defined(__arm64__)
864 // return control to hibernate_machine_entrypoint
865 return 0;
b0d623f7
A
866#else
867// implement me
868#endif
3a60a9f5 869#endif
3a60a9f5 870}
6d2010ae
A
871
872#if CONFIG_DEBUG
873/* standalone printf implementation */
874/*-
875 * Copyright (c) 1986, 1988, 1991, 1993
876 * The Regents of the University of California. All rights reserved.
877 * (c) UNIX System Laboratories, Inc.
878 * All or some portions of this file are derived from material licensed
879 * to the University of California by American Telephone and Telegraph
880 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
881 * the permission of UNIX System Laboratories, Inc.
882 *
883 * Redistribution and use in source and binary forms, with or without
884 * modification, are permitted provided that the following conditions
885 * are met:
886 * 1. Redistributions of source code must retain the above copyright
887 * notice, this list of conditions and the following disclaimer.
888 * 2. Redistributions in binary form must reproduce the above copyright
889 * notice, this list of conditions and the following disclaimer in the
890 * documentation and/or other materials provided with the distribution.
891 * 4. Neither the name of the University nor the names of its contributors
892 * may be used to endorse or promote products derived from this software
893 * without specific prior written permission.
894 *
895 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
896 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
897 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
898 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
899 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
900 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
901 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
902 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
903 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
904 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
905 * SUCH DAMAGE.
906 *
907 * @(#)subr_prf.c 8.3 (Berkeley) 1/21/94
908 */
909
910typedef long ptrdiff_t;
911char const hibhex2ascii_data[] = "0123456789abcdefghijklmnopqrstuvwxyz";
912#define hibhex2ascii(hex) (hibhex2ascii_data[hex])
913#define toupper(c) ((c) - 0x20 * (((c) >= 'a') && ((c) <= 'z')))
914static size_t
915hibstrlen(const char *s)
916{
917 size_t l = 0;
0a7de745 918 while (*s++) {
6d2010ae 919 l++;
0a7de745 920 }
6d2010ae
A
921 return l;
922}
923
924/* Max number conversion buffer length: a u_quad_t in base 2, plus NUL byte. */
0a7de745 925#define MAXNBUF (sizeof(intmax_t) * NBBY + 1)
6d2010ae
A
926
927/*
928 * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse
929 * order; return an optional length and a pointer to the last character
930 * written in the buffer (i.e., the first character of the string).
931 * The buffer pointed to by `nbuf' must have length >= MAXNBUF.
932 */
933static char *
934ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper)
935{
936 char *p, c;
937
938 /* Truncate so we don't call umoddi3, which isn't in __HIB */
939#if !defined(__LP64__)
940 uint32_t num2 = (uint32_t) num;
941#else
942 uintmax_t num2 = num;
943#endif
944
945 p = nbuf;
946 *p = '\0';
947 do {
948 c = hibhex2ascii(num2 % base);
949 *++p = upper ? toupper(c) : c;
950 } while (num2 /= base);
0a7de745 951 if (lenp) {
6d2010ae 952 *lenp = (int)(p - nbuf);
0a7de745
A
953 }
954 return p;
6d2010ae
A
955}
956
957/*
958 * Scaled down version of printf(3).
959 *
960 * Two additional formats:
961 *
962 * The format %b is supported to decode error registers.
963 * Its usage is:
964 *
f427ee49 965 * printf("reg=%b\n", regval, "<base><arg>*");
6d2010ae 966 *
f427ee49 967 * where <base> is the output base expressed as a control character, e.g.
6d2010ae
A
968 * \10 gives octal; \20 gives hex. Each arg is a sequence of characters,
969 * the first of which gives the bit number to be inspected (origin 1), and
970 * the next characters (up to a control character, i.e. a character <= 32),
971 * give the name of the register. Thus:
972 *
f427ee49 973 * kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE");
6d2010ae
A
974 *
975 * would produce output:
976 *
f427ee49 977 * reg=3<BITTWO,BITONE>
6d2010ae
A
978 *
979 * XXX: %D -- Hexdump, takes pointer and separator string:
980 * ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX
981 * ("%*D", len, ptr, " " -> XX XX XX XX ...
982 */
983static int
984hibkvprintf(char const *fmt, void (*func)(int, void*), void *arg, int radix, va_list ap)
985{
f427ee49 986#define PCHAR(c) {int cc=(c); if (func) (*func)(cc,arg); else *d++ = (char)cc; retval++; }
6d2010ae
A
987 char nbuf[MAXNBUF];
988 char *d;
989 const char *p, *percent, *q;
990 u_char *up;
991 int ch, n;
992 uintmax_t num;
993 int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
994 int cflag, hflag, jflag, tflag, zflag;
995 int dwidth, upper;
996 char padc;
997 int stop = 0, retval = 0;
998
999 num = 0;
0a7de745 1000 if (!func) {
6d2010ae 1001 d = (char *) arg;
0a7de745 1002 } else {
6d2010ae 1003 d = NULL;
0a7de745 1004 }
6d2010ae 1005
0a7de745 1006 if (fmt == NULL) {
6d2010ae 1007 fmt = "(fmt null)\n";
0a7de745 1008 }
6d2010ae 1009
0a7de745 1010 if (radix < 2 || radix > 36) {
6d2010ae 1011 radix = 10;
0a7de745 1012 }
6d2010ae
A
1013
1014 for (;;) {
1015 padc = ' ';
1016 width = 0;
0a7de745
A
1017 while ((ch = (u_char) * fmt++) != '%' || stop) {
1018 if (ch == '\0') {
1019 return retval;
1020 }
6d2010ae
A
1021 PCHAR(ch);
1022 }
1023 percent = fmt - 1;
1024 qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
1025 sign = 0; dot = 0; dwidth = 0; upper = 0;
1026 cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0;
0a7de745 1027reswitch: switch (ch = (u_char) * fmt++) {
6d2010ae
A
1028 case '.':
1029 dot = 1;
1030 goto reswitch;
1031 case '#':
1032 sharpflag = 1;
1033 goto reswitch;
1034 case '+':
1035 sign = 1;
1036 goto reswitch;
1037 case '-':
1038 ladjust = 1;
1039 goto reswitch;
1040 case '%':
1041 PCHAR(ch);
1042 break;
1043 case '*':
1044 if (!dot) {
1045 width = va_arg(ap, int);
1046 if (width < 0) {
1047 ladjust = !ladjust;
1048 width = -width;
1049 }
1050 } else {
1051 dwidth = va_arg(ap, int);
1052 }
1053 goto reswitch;
1054 case '0':
1055 if (!dot) {
1056 padc = '0';
1057 goto reswitch;
1058 }
1059 case '1': case '2': case '3': case '4':
1060 case '5': case '6': case '7': case '8': case '9':
0a7de745
A
1061 for (n = 0;; ++fmt) {
1062 n = n * 10 + ch - '0';
1063 ch = *fmt;
1064 if (ch < '0' || ch > '9') {
1065 break;
6d2010ae 1066 }
0a7de745
A
1067 }
1068 if (dot) {
6d2010ae 1069 dwidth = n;
0a7de745 1070 } else {
6d2010ae 1071 width = n;
0a7de745 1072 }
6d2010ae
A
1073 goto reswitch;
1074 case 'b':
1075 num = (u_int)va_arg(ap, int);
1076 p = va_arg(ap, char *);
0a7de745 1077 for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;) {
6d2010ae 1078 PCHAR(*q--);
0a7de745 1079 }
6d2010ae 1080
0a7de745 1081 if (num == 0) {
6d2010ae 1082 break;
0a7de745 1083 }
6d2010ae
A
1084
1085 for (tmp = 0; *p;) {
1086 n = *p++;
1087 if (num & (1 << (n - 1))) {
1088 PCHAR(tmp ? ',' : '<');
0a7de745 1089 for (; (n = *p) > ' '; ++p) {
6d2010ae 1090 PCHAR(n);
0a7de745 1091 }
6d2010ae 1092 tmp = 1;
0a7de745
A
1093 } else {
1094 for (; *p > ' '; ++p) {
6d2010ae 1095 continue;
0a7de745
A
1096 }
1097 }
6d2010ae 1098 }
0a7de745 1099 if (tmp) {
6d2010ae 1100 PCHAR('>');
0a7de745 1101 }
6d2010ae
A
1102 break;
1103 case 'c':
1104 PCHAR(va_arg(ap, int));
1105 break;
1106 case 'D':
1107 up = va_arg(ap, u_char *);
1108 p = va_arg(ap, char *);
0a7de745 1109 if (!width) {
6d2010ae 1110 width = 16;
0a7de745
A
1111 }
1112 while (width--) {
6d2010ae
A
1113 PCHAR(hibhex2ascii(*up >> 4));
1114 PCHAR(hibhex2ascii(*up & 0x0f));
1115 up++;
0a7de745
A
1116 if (width) {
1117 for (q = p; *q; q++) {
6d2010ae 1118 PCHAR(*q);
0a7de745
A
1119 }
1120 }
6d2010ae
A
1121 }
1122 break;
1123 case 'd':
1124 case 'i':
1125 base = 10;
1126 sign = 1;
1127 goto handle_sign;
1128 case 'h':
1129 if (hflag) {
1130 hflag = 0;
1131 cflag = 1;
0a7de745 1132 } else {
6d2010ae 1133 hflag = 1;
0a7de745 1134 }
6d2010ae
A
1135 goto reswitch;
1136 case 'j':
1137 jflag = 1;
1138 goto reswitch;
1139 case 'l':
1140 if (lflag) {
1141 lflag = 0;
1142 qflag = 1;
0a7de745 1143 } else {
6d2010ae 1144 lflag = 1;
0a7de745 1145 }
6d2010ae
A
1146 goto reswitch;
1147 case 'n':
0a7de745 1148 if (jflag) {
6d2010ae 1149 *(va_arg(ap, intmax_t *)) = retval;
0a7de745 1150 } else if (qflag) {
6d2010ae 1151 *(va_arg(ap, quad_t *)) = retval;
0a7de745 1152 } else if (lflag) {
6d2010ae 1153 *(va_arg(ap, long *)) = retval;
0a7de745 1154 } else if (zflag) {
6d2010ae 1155 *(va_arg(ap, size_t *)) = retval;
0a7de745 1156 } else if (hflag) {
f427ee49 1157 *(va_arg(ap, short *)) = (short)retval;
0a7de745 1158 } else if (cflag) {
f427ee49 1159 *(va_arg(ap, char *)) = (char)retval;
0a7de745 1160 } else {
6d2010ae 1161 *(va_arg(ap, int *)) = retval;
0a7de745 1162 }
6d2010ae
A
1163 break;
1164 case 'o':
1165 base = 8;
1166 goto handle_nosign;
1167 case 'p':
1168 base = 16;
1169 sharpflag = (width == 0);
1170 sign = 0;
1171 num = (uintptr_t)va_arg(ap, void *);
1172 goto number;
1173 case 'q':
1174 qflag = 1;
1175 goto reswitch;
1176 case 'r':
1177 base = radix;
0a7de745 1178 if (sign) {
6d2010ae 1179 goto handle_sign;
0a7de745 1180 }
6d2010ae
A
1181 goto handle_nosign;
1182 case 's':
1183 p = va_arg(ap, char *);
0a7de745 1184 if (p == NULL) {
6d2010ae 1185 p = "(null)";
0a7de745
A
1186 }
1187 if (!dot) {
1188 n = (typeof(n))hibstrlen(p);
1189 } else {
1190 for (n = 0; n < dwidth && p[n]; n++) {
6d2010ae 1191 continue;
0a7de745
A
1192 }
1193 }
6d2010ae
A
1194
1195 width -= n;
1196
0a7de745
A
1197 if (!ladjust && width > 0) {
1198 while (width--) {
6d2010ae 1199 PCHAR(padc);
0a7de745
A
1200 }
1201 }
1202 while (n--) {
6d2010ae 1203 PCHAR(*p++);
0a7de745
A
1204 }
1205 if (ladjust && width > 0) {
1206 while (width--) {
6d2010ae 1207 PCHAR(padc);
0a7de745
A
1208 }
1209 }
6d2010ae
A
1210 break;
1211 case 't':
1212 tflag = 1;
1213 goto reswitch;
1214 case 'u':
1215 base = 10;
1216 goto handle_nosign;
1217 case 'X':
1218 upper = 1;
1219 case 'x':
1220 base = 16;
1221 goto handle_nosign;
1222 case 'y':
1223 base = 16;
1224 sign = 1;
1225 goto handle_sign;
1226 case 'z':
1227 zflag = 1;
1228 goto reswitch;
1229handle_nosign:
1230 sign = 0;
0a7de745 1231 if (jflag) {
6d2010ae 1232 num = va_arg(ap, uintmax_t);
0a7de745 1233 } else if (qflag) {
6d2010ae 1234 num = va_arg(ap, u_quad_t);
0a7de745 1235 } else if (tflag) {
6d2010ae 1236 num = va_arg(ap, ptrdiff_t);
0a7de745 1237 } else if (lflag) {
6d2010ae 1238 num = va_arg(ap, u_long);
0a7de745 1239 } else if (zflag) {
6d2010ae 1240 num = va_arg(ap, size_t);
0a7de745 1241 } else if (hflag) {
6d2010ae 1242 num = (u_short)va_arg(ap, int);
0a7de745 1243 } else if (cflag) {
6d2010ae 1244 num = (u_char)va_arg(ap, int);
0a7de745 1245 } else {
6d2010ae 1246 num = va_arg(ap, u_int);
0a7de745 1247 }
6d2010ae
A
1248 goto number;
1249handle_sign:
0a7de745 1250 if (jflag) {
6d2010ae 1251 num = va_arg(ap, intmax_t);
0a7de745 1252 } else if (qflag) {
6d2010ae 1253 num = va_arg(ap, quad_t);
0a7de745 1254 } else if (tflag) {
6d2010ae 1255 num = va_arg(ap, ptrdiff_t);
0a7de745 1256 } else if (lflag) {
6d2010ae 1257 num = va_arg(ap, long);
0a7de745 1258 } else if (zflag) {
6d2010ae 1259 num = va_arg(ap, ssize_t);
0a7de745 1260 } else if (hflag) {
6d2010ae 1261 num = (short)va_arg(ap, int);
0a7de745 1262 } else if (cflag) {
6d2010ae 1263 num = (char)va_arg(ap, int);
0a7de745 1264 } else {
6d2010ae 1265 num = va_arg(ap, int);
0a7de745 1266 }
6d2010ae
A
1267number:
1268 if (sign && (intmax_t)num < 0) {
1269 neg = 1;
1270 num = -(intmax_t)num;
1271 }
1272 p = ksprintn(nbuf, num, base, &tmp, upper);
1273 if (sharpflag && num != 0) {
0a7de745 1274 if (base == 8) {
6d2010ae 1275 tmp++;
0a7de745 1276 } else if (base == 16) {
6d2010ae 1277 tmp += 2;
0a7de745 1278 }
6d2010ae 1279 }
0a7de745 1280 if (neg) {
6d2010ae 1281 tmp++;
0a7de745 1282 }
6d2010ae
A
1283
1284 if (!ladjust && padc != '0' && width
0a7de745
A
1285 && (width -= tmp) > 0) {
1286 while (width--) {
6d2010ae 1287 PCHAR(padc);
0a7de745
A
1288 }
1289 }
1290 if (neg) {
6d2010ae 1291 PCHAR('-');
0a7de745 1292 }
6d2010ae
A
1293 if (sharpflag && num != 0) {
1294 if (base == 8) {
1295 PCHAR('0');
1296 } else if (base == 16) {
1297 PCHAR('0');
1298 PCHAR('x');
1299 }
1300 }
0a7de745
A
1301 if (!ladjust && width && (width -= tmp) > 0) {
1302 while (width--) {
6d2010ae 1303 PCHAR(padc);
0a7de745
A
1304 }
1305 }
6d2010ae 1306
0a7de745 1307 while (*p) {
6d2010ae 1308 PCHAR(*p--);
0a7de745 1309 }
6d2010ae 1310
0a7de745
A
1311 if (ladjust && width && (width -= tmp) > 0) {
1312 while (width--) {
6d2010ae 1313 PCHAR(padc);
0a7de745
A
1314 }
1315 }
6d2010ae
A
1316
1317 break;
1318 default:
0a7de745 1319 while (percent < fmt) {
6d2010ae 1320 PCHAR(*percent++);
0a7de745 1321 }
6d2010ae 1322 /*
f427ee49 1323 * Since we ignore a formatting argument it is no
6d2010ae
A
1324 * longer safe to obey the remaining formatting
1325 * arguments as the arguments will no longer match
1326 * the format specs.
1327 */
1328 stop = 1;
1329 break;
1330 }
1331 }
1332#undef PCHAR
1333}
1334
1335
1336static void
1337putchar(int c, void *arg)
1338{
1339 (void)arg;
f427ee49 1340 hib_uart_putc((char)c);
6d2010ae
A
1341}
1342
1343void
1344hibprintf(const char *fmt, ...)
1345{
1346 /* http://www.pagetable.com/?p=298 */
1347 va_list ap;
1348
1349 va_start(ap, fmt);
1350 hibkvprintf(fmt, putchar, NULL, 10, ap);
1351 va_end(ap);
1352}
1353#endif /* CONFIG_DEBUG */
f427ee49
A
1354
1355#if __arm64__ && HIBERNATE_TRAP_HANDLER
1356void
1357hibernate_trap(__unused arm_context_t *context, __unused uint64_t trap_addr)
1358__attribute__((optnone))
1359{
1360 // enable logging
1361 gIOHibernateDebugFlags |= kIOHibernateDebugRestoreLogs;
1362
1363 // dump some interesting registers
1364 for (int i = 0; i < 29; i++) {
1365 debug_code(' r00' + (i / 10 * 256) + (i % 10), context->ss.ss_64.x[i]);
1366 }
1367 debug_code(' fp', context->ss.ss_64.fp);
1368 debug_code(' lr', context->ss.ss_64.lr);
1369 debug_code(' sp', context->ss.ss_64.sp);
1370 debug_code(' pc', context->ss.ss_64.pc);
1371 debug_code('cpsr', context->ss.ss_64.cpsr);
1372 debug_code('asps', context->ss.ss_64.aspsr);
1373 debug_code(' far', context->ss.ss_64.far);
1374 debug_code(' esr', context->ss.ss_64.esr);
1375
1376 // dump the trap_addr
1377 debug_code('trap', trap_addr);
1378
1379 // dump the kernel slide
1380 debug_code('slid', _hibernateHeader.kernVirtSlide);
1381
1382 // loop forever
1383 while (true) {
1384 ;
1385 }
1386}
1387#endif /* __arm64__ && HIBERNATE_TRAP_HANDLER */