]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOHibernateIO.cpp
xnu-1699.22.73.tar.gz
[apple/xnu.git] / iokit / Kernel / IOHibernateIO.cpp
1 /*
2 * Copyright (c) 2004-2008 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29
30 /*
31
32 Sleep:
33
34 - PMRootDomain calls IOHibernateSystemSleep() before system sleep
35 (devices awake, normal execution context)
36 - IOHibernateSystemSleep opens the hibernation file (or partition) at the bsd level,
37 grabs its extents and searches for a polling driver willing to work with that IOMedia.
38 The BSD code makes an ioctl to the storage driver to get the partition base offset to
39 the disk, and other ioctls to get the transfer constraints
40 If successful, the file is written to make sure its initially not bootable (in case of
41 later failure) and nvram set to point to the first block of the file. (Has to be done
42 here so blocking is possible in nvram support).
43 hibernate_setup() in osfmk is called to allocate page bitmaps for all dram, and
44 page out any pages it wants to (currently zero, but probably some percentage of memory).
45 Its assumed just allocating pages will cause the VM system to naturally select the best
46 pages for eviction. It also copies processor flags needed for the restore path and sets
47 a flag in the boot processor proc info.
48 gIOHibernateState = kIOHibernateStateHibernating.
49 - Regular sleep progresses - some drivers may inspect the root domain property
50 kIOHibernateStateKey to modify behavior. The platform driver saves state to memory
51 as usual but leaves motherboard I/O on.
52 - Eventually the platform calls ml_ppc_sleep() in the shutdown context on the last cpu,
53 at which point memory is ready to be saved. mapping_hibernate_flush() is called to get
54 all ppc RC bits out of the hash table and caches into the mapping structures.
55 - hibernate_write_image() is called (still in shutdown context, no blocking or preemption).
56 hibernate_page_list_setall() is called to get a bitmap of dram pages that need to be saved.
57 All pages are assumed to be saved (as part of the wired image) unless explicitly subtracted
58 by hibernate_page_list_setall(), avoiding having to find arch dependent low level bits.
59 The image header and block list are written. The header includes the second file extent so
60 only the header block is needed to read the file, regardless of filesystem.
61 The kernel section "__HIB" is written uncompressed to the image. This section of code and data
62 (only) is used to decompress the image during wake/boot.
63 Some additional pages are removed from the bitmaps - the buffers used for hibernation.
64 The bitmaps are written to the image.
65 More areas are removed from the bitmaps (after they have been written to the image) - the
66 section "__HIB" pages and interrupt stack.
67 Each wired page is compressed and written and then each non-wired page. Compression and
68 disk writes are in parallel.
69 The image header is written to the start of the file and the polling driver closed.
70 The machine powers down (or sleeps).
71
72 Boot/Wake:
73
74 - BootX sees the boot-image nvram variable containing the device and block number of the image,
75 reads the header and if the signature is correct proceeds. The boot-image variable is cleared.
76 - BootX reads the portion of the image used for wired pages, to memory. Its assumed this will fit
77 in the OF memory environment, and the image is decrypted. There is no decompression in BootX,
78 that is in the kernel's __HIB section.
79 - BootX copies the "__HIB" section to its correct position in memory, quiesces and calls its entry
80 hibernate_kernel_entrypoint(), passing the location of the image in memory. Translation is off,
81 only code & data in that section is safe to call since all the other wired pages are still
82 compressed in the image.
83 - hibernate_kernel_entrypoint() removes pages occupied by the raw image from the page bitmaps.
84 It uses the bitmaps to work out which pages can be uncompressed from the image to their final
85 location directly, and copies those that can't to interim free pages. When the image has been
86 completed, the copies are uncompressed, overwriting the wired image pages.
87 hibernate_restore_phys_page() (in osfmk since its arch dependent, but part of the "__HIB" section)
88 is used to get pages into place for 64bit.
89 - the reset vector is called (at least on ppc), the kernel proceeds on a normal wake, with some
90 changes conditional on the per proc flag - before VM is turned on the boot cpu, all mappings
91 are removed from the software strutures, and the hash table is reinitialized.
92 - After the platform CPU init code is called, hibernate_machine_init() is called to restore the rest
93 of memory, using the polled mode driver, before other threads can run or any devices are turned on.
94 This reduces the memory usage for BootX and allows decompression in parallel with disk reads,
95 for the remaining non wired pages.
96 - The polling driver is closed down and regular wake proceeds. When the kernel calls iokit to wake
97 (normal execution context) hibernate_teardown() in osmfk is called to release any memory, the file
98 is closed via bsd.
99
100 Polled Mode I/O:
101
102 IOHibernateSystemSleep() finds a polled mode interface to the ATA controller via a property in the
103 registry, specifying an object of calls IOPolledInterface.
104
105 Before the system goes to sleep it searches from the IOMedia object (could be a filesystem or
106 partition) that the image is going to live, looking for polled interface properties. If it finds
107 one the IOMedia object is passed to a "probe" call for the interface to accept or reject. All the
108 interfaces found are kept in an ordered list.
109
110 There is an Open/Close pair of calls made to each of the interfaces at various stages since there are
111 few different contexts things happen in:
112
113 - there is an Open/Close (Preflight) made before any part of the system has slept (I/O is all
114 up and running) and after wake - this is safe to allocate memory and do anything. The device
115 ignores sleep requests from that point since its a waste of time if it goes to sleep and
116 immediately wakes back up for the image write.
117
118 - there is an Open/Close (BeforeSleep) pair made around the image write operations that happen
119 immediately before sleep. These can't block or allocate memory - the I/O system is asleep apart
120 from the low level bits (motherboard I/O etc). There is only one thread running. The close can be
121 used to flush and set the disk to sleep.
122
123 - there is an Open/Close (AfterSleep) pair made around the image read operations that happen
124 immediately after sleep. These can't block or allocate memory. This is happening after the platform
125 expert has woken the low level bits of the system, but most of the I/O system has not. There is only
126 one thread running.
127
128 For the actual I/O, all the ops are with respect to a single IOMemoryDescriptor that was passed
129 (prepared) to the Preflight Open() call. There is a read/write op, buffer offset to the IOMD for
130 the data, an offset to the disk and length (block aligned 64 bit numbers), and completion callback.
131 Each I/O is async but only one is ever outstanding. The polled interface has a checkForWork call
132 that is called for the hardware to check for events, and complete the I/O via the callback.
133 The hibernate path uses the same transfer constraints the regular cluster I/O path in BSD uses
134 to restrict I/O ops.
135 */
136
137 #include <sys/systm.h>
138
139 #include <IOKit/IOWorkLoop.h>
140 #include <IOKit/IOCommandGate.h>
141 #include <IOKit/IOTimerEventSource.h>
142 #include <IOKit/IOPlatformExpert.h>
143 #include <IOKit/IOKitDebug.h>
144 #include <IOKit/IOTimeStamp.h>
145 #include <IOKit/pwr_mgt/RootDomain.h>
146 #include <IOKit/pwr_mgt/IOPMPrivate.h>
147 #include <IOKit/IOMessage.h>
148 #include <IOKit/IODeviceTreeSupport.h>
149 #include <IOKit/IOBSD.h>
150 #include "RootDomainUserClient.h"
151 #include <IOKit/pwr_mgt/IOPowerConnection.h>
152 #include "IOPMPowerStateQueue.h"
153 #include <IOKit/IOBufferMemoryDescriptor.h>
154 #include <IOKit/AppleKeyStoreInterface.h>
155 #include <crypto/aes.h>
156
157 #include <sys/uio.h>
158 #include <sys/conf.h>
159 #include <sys/stat.h>
160 #include <sys/fcntl.h> // (FWRITE, ...)
161 #include <sys/sysctl.h>
162 #include <sys/kdebug.h>
163
164 #include <IOKit/IOHibernatePrivate.h>
165 #include <IOKit/IOPolledInterface.h>
166 #include <IOKit/IONVRAM.h>
167 #include "IOHibernateInternal.h"
168 #include <libkern/WKdm.h>
169 #include "IOKitKernelInternal.h"
170 #include <pexpert/device_tree.h>
171
172 #include <machine/pal_routines.h>
173 #include <machine/pal_hibernate.h>
174
175 extern "C" addr64_t kvtophys(vm_offset_t va);
176
177 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
178
179 extern unsigned int save_kdebug_enable;
180 extern uint32_t gIOHibernateState;
181 uint32_t gIOHibernateMode;
182 static char gIOHibernateBootSignature[256+1];
183 static char gIOHibernateFilename[MAXPATHLEN+1];
184 static uint32_t gIOHibernateFreeRatio = 0; // free page target (percent)
185 uint32_t gIOHibernateFreeTime = 0*1000; // max time to spend freeing pages (ms)
186
187 static IODTNVRAM * gIOOptionsEntry;
188 static IORegistryEntry * gIOChosenEntry;
189 #if defined(__i386__) || defined(__x86_64__)
190 static const OSSymbol * gIOCreateEFIDevicePathSymbol;
191 static const OSSymbol * gIOHibernateRTCVariablesKey;
192 static const OSSymbol * gIOHibernateBoot0082Key;
193 static const OSSymbol * gIOHibernateBootNextKey;
194 static OSData * gIOHibernateBoot0082Data;
195 static OSData * gIOHibernateBootNextData;
196 static OSObject * gIOHibernateBootNextSave;
197 #endif
198
199 static IOPolledFileIOVars gFileVars;
200 static IOHibernateVars gIOHibernateVars;
201 static struct kern_direct_file_io_ref_t * gIOHibernateFileRef;
202 static hibernate_cryptvars_t gIOHibernateCryptWakeContext;
203 static hibernate_graphics_t _hibernateGraphics;
204 static hibernate_graphics_t * gIOHibernateGraphicsInfo = &_hibernateGraphics;
205
206 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
207
208 enum { kXPRamAudioVolume = 8 };
209 enum { kDefaultIOSize = 128 * 1024 };
210 enum { kVideoMapSize = 32 * 1024 * 1024 };
211
212 #ifndef kIOMediaPreferredBlockSizeKey
213 #define kIOMediaPreferredBlockSizeKey "Preferred Block Size"
214 #endif
215
216 #ifndef kIOBootPathKey
217 #define kIOBootPathKey "bootpath"
218 #endif
219 #ifndef kIOSelectedBootDeviceKey
220 #define kIOSelectedBootDeviceKey "boot-device"
221 #endif
222
223
224 enum { kIOHibernateMinPollersNeeded = 2 };
225
226 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
227
228 // copy from phys addr to MD
229
230 static IOReturn
231 IOMemoryDescriptorWriteFromPhysical(IOMemoryDescriptor * md,
232 IOByteCount offset, addr64_t bytes, IOByteCount length)
233 {
234 addr64_t srcAddr = bytes;
235 IOByteCount remaining;
236
237 remaining = length = min(length, md->getLength() - offset);
238 while (remaining) { // (process another target segment?)
239 addr64_t dstAddr64;
240 IOByteCount dstLen;
241
242 dstAddr64 = md->getPhysicalSegment(offset, &dstLen, kIOMemoryMapperNone);
243 if (!dstAddr64)
244 break;
245
246 // Clip segment length to remaining
247 if (dstLen > remaining)
248 dstLen = remaining;
249
250 #if 1
251 bcopy_phys(srcAddr, dstAddr64, dstLen);
252 #else
253 copypv(srcAddr, dstAddr64, dstLen,
254 cppvPsnk | cppvFsnk | cppvNoRefSrc | cppvNoModSnk | cppvKmap);
255 #endif
256 srcAddr += dstLen;
257 offset += dstLen;
258 remaining -= dstLen;
259 }
260
261 assert(!remaining);
262
263 return remaining ? kIOReturnUnderrun : kIOReturnSuccess;
264 }
265
266 // copy from MD to phys addr
267
268 static IOReturn
269 IOMemoryDescriptorReadToPhysical(IOMemoryDescriptor * md,
270 IOByteCount offset, addr64_t bytes, IOByteCount length)
271 {
272 addr64_t dstAddr = bytes;
273 IOByteCount remaining;
274
275 remaining = length = min(length, md->getLength() - offset);
276 while (remaining) { // (process another target segment?)
277 addr64_t srcAddr64;
278 IOByteCount dstLen;
279
280 srcAddr64 = md->getPhysicalSegment(offset, &dstLen, kIOMemoryMapperNone);
281 if (!srcAddr64)
282 break;
283
284 // Clip segment length to remaining
285 if (dstLen > remaining)
286 dstLen = remaining;
287
288 #if 1
289 bcopy_phys(srcAddr64, dstAddr, dstLen);
290 #else
291 copypv(srcAddr, dstAddr64, dstLen,
292 cppvPsnk | cppvFsnk | cppvNoRefSrc | cppvNoModSnk | cppvKmap);
293 #endif
294 dstAddr += dstLen;
295 offset += dstLen;
296 remaining -= dstLen;
297 }
298
299 assert(!remaining);
300
301 return remaining ? kIOReturnUnderrun : kIOReturnSuccess;
302 }
303
304 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
305
306 void
307 hibernate_set_page_state(hibernate_page_list_t * page_list, hibernate_page_list_t * page_list_wired,
308 vm_offset_t ppnum, vm_offset_t count, uint32_t kind)
309 {
310 count += ppnum;
311 switch (kind)
312 {
313 case kIOHibernatePageStateUnwiredSave:
314 // unwired save
315 for (; ppnum < count; ppnum++)
316 {
317 hibernate_page_bitset(page_list, FALSE, ppnum);
318 hibernate_page_bitset(page_list_wired, TRUE, ppnum);
319 }
320 break;
321 case kIOHibernatePageStateWiredSave:
322 // wired save
323 for (; ppnum < count; ppnum++)
324 {
325 hibernate_page_bitset(page_list, FALSE, ppnum);
326 hibernate_page_bitset(page_list_wired, FALSE, ppnum);
327 }
328 break;
329 case kIOHibernatePageStateFree:
330 // free page
331 for (; ppnum < count; ppnum++)
332 {
333 hibernate_page_bitset(page_list, TRUE, ppnum);
334 hibernate_page_bitset(page_list_wired, TRUE, ppnum);
335 }
336 break;
337 default:
338 panic("hibernate_set_page_state");
339 }
340 }
341
342 static vm_offset_t
343 hibernate_page_list_iterate(hibernate_page_list_t * list, vm_offset_t * pPage)
344 {
345 uint32_t page = *pPage;
346 uint32_t count;
347 hibernate_bitmap_t * bitmap;
348
349 while ((bitmap = hibernate_page_bitmap_pin(list, &page)))
350 {
351 count = hibernate_page_bitmap_count(bitmap, TRUE, page);
352 if (!count)
353 break;
354 page += count;
355 if (page <= bitmap->last_page)
356 break;
357 }
358
359 *pPage = page;
360 if (bitmap)
361 count = hibernate_page_bitmap_count(bitmap, FALSE, page);
362 else
363 count = 0;
364
365 return (count);
366 }
367
368 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
369
370 static IOReturn
371 IOHibernatePollerProbe(IOPolledFileIOVars * vars, IOService * target)
372 {
373 IOReturn err = kIOReturnError;
374 int32_t idx;
375 IOPolledInterface * poller;
376
377 for (idx = vars->pollers->getCount() - 1; idx >= 0; idx--)
378 {
379 poller = (IOPolledInterface *) vars->pollers->getObject(idx);
380 err = poller->probe(target);
381 if (err)
382 {
383 HIBLOG("IOPolledInterface::probe[%d] 0x%x\n", idx, err);
384 break;
385 }
386 }
387
388 return (err);
389 }
390
391 static IOReturn
392 IOHibernatePollerOpen(IOPolledFileIOVars * vars, uint32_t state, IOMemoryDescriptor * md)
393 {
394 IOReturn err = kIOReturnError;
395 int32_t idx;
396 IOPolledInterface * poller;
397
398 for (idx = vars->pollers->getCount() - 1; idx >= 0; idx--)
399 {
400 poller = (IOPolledInterface *) vars->pollers->getObject(idx);
401 err = poller->open(state, md);
402 if (err)
403 {
404 HIBLOG("IOPolledInterface::open[%d] 0x%x\n", idx, err);
405 break;
406 }
407 }
408
409 return (err);
410 }
411
412 static IOReturn
413 IOHibernatePollerClose(IOPolledFileIOVars * vars, uint32_t state)
414 {
415 IOReturn err = kIOReturnError;
416 int32_t idx;
417 IOPolledInterface * poller;
418
419 for (idx = 0;
420 (poller = (IOPolledInterface *) vars->pollers->getObject(idx));
421 idx++)
422 {
423 err = poller->close(state);
424 if (err)
425 HIBLOG("IOPolledInterface::close[%d] 0x%x\n", idx, err);
426 }
427
428 return (err);
429 }
430
431 static void
432 IOHibernatePollerIOComplete(void * target,
433 void * parameter,
434 IOReturn status,
435 UInt64 actualByteCount)
436 {
437 IOPolledFileIOVars * vars = (IOPolledFileIOVars *) parameter;
438
439 vars->ioStatus = status;
440 }
441
442 static IOReturn
443 IOHibernatePollerIO(IOPolledFileIOVars * vars,
444 uint32_t operation, uint32_t bufferOffset,
445 uint64_t deviceOffset, uint64_t length)
446 {
447
448 IOReturn err = kIOReturnError;
449 IOPolledInterface * poller;
450 IOPolledCompletion completion;
451
452 completion.target = 0;
453 completion.action = &IOHibernatePollerIOComplete;
454 completion.parameter = vars;
455
456 vars->ioStatus = -1;
457
458 poller = (IOPolledInterface *) vars->pollers->getObject(0);
459 err = poller->startIO(operation, bufferOffset, deviceOffset + vars->block0, length, completion);
460 if (err)
461 HIBLOG("IOPolledInterface::startIO[%d] 0x%x\n", 0, err);
462
463 return (err);
464 }
465
466 static IOReturn
467 IOHibernatePollerIODone(IOPolledFileIOVars * vars, bool abortable)
468 {
469 IOReturn err = kIOReturnSuccess;
470 int32_t idx = 0;
471 IOPolledInterface * poller;
472
473 while (-1 == vars->ioStatus)
474 {
475 for (idx = 0;
476 (poller = (IOPolledInterface *) vars->pollers->getObject(idx));
477 idx++)
478 {
479 IOReturn newErr;
480 newErr = poller->checkForWork();
481 if ((newErr == kIOReturnAborted) && !abortable)
482 newErr = kIOReturnSuccess;
483 if (kIOReturnSuccess == err)
484 err = newErr;
485 }
486 }
487
488 if ((kIOReturnSuccess == err) && abortable && hibernate_should_abort())
489 {
490 err = kIOReturnAborted;
491 HIBLOG("IOPolledInterface::checkForWork sw abort\n");
492 }
493
494 if (err)
495 {
496 HIBLOG("IOPolledInterface::checkForWork[%d] 0x%x\n", idx, err);
497 }
498 else
499 {
500 err = vars->ioStatus;
501 if (kIOReturnSuccess != err)
502 HIBLOG("IOPolledInterface::ioStatus 0x%x\n", err);
503 }
504
505 return (err);
506 }
507
508 IOReturn
509 IOPolledInterface::checkAllForWork(void)
510 {
511 IOReturn err = kIOReturnNotReady;
512 int32_t idx;
513 IOPolledInterface * poller;
514
515 IOHibernateVars * vars = &gIOHibernateVars;
516
517 if (!vars->fileVars || !vars->fileVars->pollers)
518 return (err);
519
520 for (idx = 0;
521 (poller = (IOPolledInterface *) vars->fileVars->pollers->getObject(idx));
522 idx++)
523 {
524 err = poller->checkForWork();
525 if (err)
526 HIBLOG("IOPolledInterface::checkAllForWork[%d] 0x%x\n", idx, err);
527 }
528
529 return (err);
530 }
531
532 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
533
534 struct _OpenFileContext
535 {
536 OSData * extents;
537 uint64_t size;
538 };
539
540 static void
541 file_extent_callback(void * ref, uint64_t start, uint64_t length)
542 {
543 _OpenFileContext * ctx = (_OpenFileContext *) ref;
544 IOPolledFileExtent extent;
545
546 extent.start = start;
547 extent.length = length;
548
549 ctx->extents->appendBytes(&extent, sizeof(extent));
550 ctx->size += length;
551 }
552
553 static IOService *
554 IOCopyMediaForDev(dev_t device)
555 {
556 OSDictionary * matching;
557 OSNumber * num;
558 OSIterator * iter;
559 IOService * result = 0;
560
561 matching = IOService::serviceMatching("IOMedia");
562 if (!matching)
563 return (0);
564 do
565 {
566 num = OSNumber::withNumber(major(device), 32);
567 if (!num)
568 break;
569 matching->setObject(kIOBSDMajorKey, num);
570 num->release();
571 num = OSNumber::withNumber(minor(device), 32);
572 if (!num)
573 break;
574 matching->setObject(kIOBSDMinorKey, num);
575 num->release();
576 if (!num)
577 break;
578 iter = IOService::getMatchingServices(matching);
579 if (iter)
580 {
581 result = (IOService *) iter->getNextObject();
582 result->retain();
583 iter->release();
584 }
585 }
586 while (false);
587 matching->release();
588
589 return (result);
590 }
591
592 IOReturn
593 IOPolledFileOpen( const char * filename, IOBufferMemoryDescriptor * ioBuffer,
594 IOPolledFileIOVars ** fileVars, OSData ** fileExtents,
595 OSData ** imagePath, uint8_t * volumeCryptKey)
596 {
597 IOReturn err = kIOReturnError;
598 IOPolledFileIOVars * vars;
599 _OpenFileContext ctx;
600 OSData * extentsData;
601 OSNumber * num;
602 IOService * part = 0;
603 OSString * keyUUID = 0;
604 OSString * keyStoreUUID = 0;
605 dev_t block_dev;
606 dev_t hibernate_image_dev;
607 uint64_t maxiobytes;
608
609 vars = &gFileVars;
610 do
611 {
612 HIBLOG("sizeof(IOHibernateImageHeader) == %ld\n", sizeof(IOHibernateImageHeader));
613 if (sizeof(IOHibernateImageHeader) != 512)
614 continue;
615
616 vars->io = false;
617 vars->buffer = (uint8_t *) ioBuffer->getBytesNoCopy();
618 vars->bufferHalf = 0;
619 vars->bufferOffset = 0;
620 vars->bufferSize = ioBuffer->getLength() >> 1;
621
622 extentsData = OSData::withCapacity(32);
623
624 ctx.extents = extentsData;
625 ctx.size = 0;
626 vars->fileRef = kern_open_file_for_direct_io(filename,
627 &file_extent_callback, &ctx,
628 &block_dev,
629 &hibernate_image_dev,
630 &vars->block0,
631 &maxiobytes,
632 &vars->flags,
633 0, (caddr_t) gIOHibernateCurrentHeader,
634 sizeof(IOHibernateImageHeader));
635 if (!vars->fileRef)
636 {
637 err = kIOReturnNoSpace;
638 break;
639 }
640 gIOHibernateFileRef = vars->fileRef;
641
642 if (kIOHibernateModeSSDInvert & gIOHibernateMode)
643 vars->flags ^= kIOHibernateOptionSSD;
644
645 HIBLOG("Opened file %s, size %qd, partition base 0x%qx, maxio %qx ssd %d\n", filename, ctx.size,
646 vars->block0, maxiobytes, kIOHibernateOptionSSD & vars->flags);
647 if (ctx.size < 1*1024*1024) // check against image size estimate!
648 {
649 err = kIOReturnNoSpace;
650 break;
651 }
652
653 if (maxiobytes < vars->bufferSize)
654 vars->bufferSize = maxiobytes;
655
656 vars->extentMap = (IOPolledFileExtent *) extentsData->getBytesNoCopy();
657
658 part = IOCopyMediaForDev(block_dev);
659 if (!part)
660 break;
661
662 err = part->callPlatformFunction(PLATFORM_FUNCTION_GET_MEDIA_ENCRYPTION_KEY_UUID, false,
663 (void *) &keyUUID, (void *) &keyStoreUUID, NULL, NULL);
664 if ((kIOReturnSuccess == err) && keyUUID && keyStoreUUID)
665 {
666 // IOLog("got volume key %s\n", keyStoreUUID->getCStringNoCopy());
667 uuid_t volumeKeyUUID;
668 aks_volume_key_t vek;
669 static IOService * sKeyStore;
670 static const OSSymbol * sAKSGetKey;
671
672 if (!sAKSGetKey)
673 sAKSGetKey = OSSymbol::withCStringNoCopy(AKS_PLATFORM_FUNCTION_GETKEY);
674 if (!sKeyStore)
675 sKeyStore = (IOService *) IORegistryEntry::fromPath(AKS_SERVICE_PATH, gIOServicePlane);
676 if (sKeyStore)
677 err = uuid_parse(keyStoreUUID->getCStringNoCopy(), volumeKeyUUID);
678 else
679 err = kIOReturnNoResources;
680 if (kIOReturnSuccess == err)
681 err = sKeyStore->callPlatformFunction(sAKSGetKey, true, volumeKeyUUID, &vek, NULL, NULL);
682 if (kIOReturnSuccess != err)
683 IOLog("volume key err 0x%x\n", err);
684 else
685 {
686 size_t bytes = (kIOHibernateAESKeySize / 8);
687 if (vek.key.keybytecount < bytes)
688 bytes = vek.key.keybytecount;
689 bcopy(&vek.key.keybytes[0], volumeCryptKey, bytes);
690 }
691 bzero(&vek, sizeof(vek));
692 }
693 part->release();
694
695 part = IOCopyMediaForDev(hibernate_image_dev);
696 if (!part)
697 break;
698
699 IORegistryEntry * next;
700 IORegistryEntry * child;
701 OSData * data;
702
703 vars->pollers = OSArray::withCapacity(4);
704 if (!vars->pollers)
705 break;
706
707 vars->blockSize = 512;
708 next = part;
709 do
710 {
711 IOPolledInterface * poller;
712 OSObject * obj;
713
714 obj = next->getProperty(kIOPolledInterfaceSupportKey);
715 if (kOSBooleanFalse == obj)
716 {
717 vars->pollers->flushCollection();
718 break;
719 }
720 else if ((poller = OSDynamicCast(IOPolledInterface, obj)))
721 vars->pollers->setObject(poller);
722 if ((num = OSDynamicCast(OSNumber, next->getProperty(kIOMediaPreferredBlockSizeKey))))
723 vars->blockSize = num->unsigned32BitValue();
724 child = next;
725 }
726 while ((next = child->getParentEntry(gIOServicePlane))
727 && child->isParent(next, gIOServicePlane, true));
728
729 HIBLOG("hibernate image major %d, minor %d, blocksize %ld, pollers %d\n",
730 major(hibernate_image_dev), minor(hibernate_image_dev), (long)vars->blockSize, vars->pollers->getCount());
731 if (vars->pollers->getCount() < kIOHibernateMinPollersNeeded)
732 continue;
733
734 err = IOHibernatePollerProbe(vars, (IOService *) part);
735 if (kIOReturnSuccess != err)
736 break;
737
738 err = IOHibernatePollerOpen(vars, kIOPolledPreflightState, ioBuffer);
739 if (kIOReturnSuccess != err)
740 break;
741
742 *fileVars = vars;
743 *fileExtents = extentsData;
744
745 // make imagePath
746
747 if ((extentsData->getLength() >= sizeof(IOPolledFileExtent)))
748 {
749 char str2[24 + sizeof(uuid_string_t) + 2];
750
751 #if defined(__i386__) || defined(__x86_64__)
752 if (!gIOCreateEFIDevicePathSymbol)
753 gIOCreateEFIDevicePathSymbol = OSSymbol::withCString("CreateEFIDevicePath");
754
755 if (keyUUID)
756 snprintf(str2, sizeof(str2), "%qx:%s",
757 vars->extentMap[0].start, keyUUID->getCStringNoCopy());
758 else
759 snprintf(str2, sizeof(str2), "%qx", vars->extentMap[0].start);
760
761 err = IOService::getPlatform()->callPlatformFunction(
762 gIOCreateEFIDevicePathSymbol, false,
763 (void *) part, (void *) str2,
764 (void *) (uintptr_t) true, (void *) &data);
765 #else
766 char str1[256];
767 int len = sizeof(str1);
768
769 if (!part->getPath(str1, &len, gIODTPlane))
770 err = kIOReturnNotFound;
771 else
772 {
773 snprintf(str2, sizeof(str2), ",%qx", vars->extentMap[0].start);
774 // (strip the plane name)
775 char * tail = strchr(str1, ':');
776 if (!tail)
777 tail = str1 - 1;
778 data = OSData::withBytes(tail + 1, strlen(tail + 1));
779 data->appendBytes(str2, strlen(str2));
780 }
781 #endif
782 if (kIOReturnSuccess == err)
783 *imagePath = data;
784 else
785 HIBLOG("error 0x%x getting path\n", err);
786 }
787 }
788 while (false);
789
790 if (kIOReturnSuccess != err)
791 {
792 HIBLOG("error 0x%x opening hibernation file\n", err);
793 if (vars->fileRef)
794 {
795 kern_close_file_for_direct_io(vars->fileRef, 0, 0, 0);
796 gIOHibernateFileRef = vars->fileRef = NULL;
797 }
798 }
799
800 if (part)
801 part->release();
802
803 return (err);
804 }
805
806 IOReturn
807 IOPolledFileClose( IOPolledFileIOVars * vars )
808 {
809 if (vars->pollers)
810 {
811 IOHibernatePollerClose(vars, kIOPolledPostflightState);
812 vars->pollers->release();
813 }
814
815 bzero(vars, sizeof(IOPolledFileIOVars));
816
817 return (kIOReturnSuccess);
818 }
819
820 static IOReturn
821 IOPolledFileSeek(IOPolledFileIOVars * vars, uint64_t position)
822 {
823 IOPolledFileExtent * extentMap;
824
825 extentMap = vars->extentMap;
826
827 vars->position = position;
828
829 while (position >= extentMap->length)
830 {
831 position -= extentMap->length;
832 extentMap++;
833 }
834
835 vars->currentExtent = extentMap;
836 vars->extentRemaining = extentMap->length - position;
837 vars->extentPosition = vars->position - position;
838
839 if (vars->bufferSize <= vars->extentRemaining)
840 vars->bufferLimit = vars->bufferSize;
841 else
842 vars->bufferLimit = vars->extentRemaining;
843
844 return (kIOReturnSuccess);
845 }
846
847 static IOReturn
848 IOPolledFileWrite(IOPolledFileIOVars * vars,
849 const uint8_t * bytes, IOByteCount size,
850 hibernate_cryptvars_t * cryptvars)
851 {
852 IOReturn err = kIOReturnSuccess;
853 IOByteCount copy;
854 bool flush = false;
855
856 do
857 {
858 if (!bytes && !size)
859 {
860 // seek to end of block & flush
861 size = vars->position & (vars->blockSize - 1);
862 if (size)
863 size = vars->blockSize - size;
864 flush = true;
865 // use some garbage for the fill
866 bytes = vars->buffer + vars->bufferOffset;
867 }
868
869 copy = vars->bufferLimit - vars->bufferOffset;
870 if (copy > size)
871 copy = size;
872 else
873 flush = true;
874
875 if (bytes)
876 {
877 bcopy(bytes, vars->buffer + vars->bufferHalf + vars->bufferOffset, copy);
878 bytes += copy;
879 }
880 else
881 bzero(vars->buffer + vars->bufferHalf + vars->bufferOffset, copy);
882
883 size -= copy;
884 vars->bufferOffset += copy;
885 vars->position += copy;
886
887 if (flush && vars->bufferOffset)
888 {
889 uint64_t offset = (vars->position - vars->bufferOffset
890 - vars->extentPosition + vars->currentExtent->start);
891 uint32_t length = (vars->bufferOffset);
892
893 #if CRYPTO
894 if (cryptvars && vars->encryptStart
895 && (vars->position > vars->encryptStart)
896 && ((vars->position - length) < vars->encryptEnd))
897 {
898 AbsoluteTime startTime, endTime;
899
900 uint32_t encryptLen, encryptStart;
901 encryptLen = vars->position - vars->encryptStart;
902 if (encryptLen > length)
903 encryptLen = length;
904 encryptStart = length - encryptLen;
905 if (vars->position > vars->encryptEnd)
906 encryptLen -= (vars->position - vars->encryptEnd);
907
908 clock_get_uptime(&startTime);
909
910 // encrypt the buffer
911 aes_encrypt_cbc(vars->buffer + vars->bufferHalf + encryptStart,
912 &cryptvars->aes_iv[0],
913 encryptLen / AES_BLOCK_SIZE,
914 vars->buffer + vars->bufferHalf + encryptStart,
915 &cryptvars->ctx.encrypt);
916
917 clock_get_uptime(&endTime);
918 ADD_ABSOLUTETIME(&vars->cryptTime, &endTime);
919 SUB_ABSOLUTETIME(&vars->cryptTime, &startTime);
920 vars->cryptBytes += encryptLen;
921
922 // save initial vector for following encrypts
923 bcopy(vars->buffer + vars->bufferHalf + encryptStart + encryptLen - AES_BLOCK_SIZE,
924 &cryptvars->aes_iv[0],
925 AES_BLOCK_SIZE);
926 }
927 #endif /* CRYPTO */
928
929 if (vars->io)
930 {
931 err = IOHibernatePollerIODone(vars, true);
932 if (kIOReturnSuccess != err)
933 break;
934 }
935
936 if (vars->position & (vars->blockSize - 1)) HIBLOG("misaligned file pos %qx\n", vars->position);
937 //if (length != vars->bufferSize) HIBLOG("short write of %qx ends@ %qx\n", length, offset + length);
938
939 err = IOHibernatePollerIO(vars, kIOPolledWrite, vars->bufferHalf, offset, length);
940 if (kIOReturnSuccess != err)
941 break;
942 vars->io = true;
943
944 vars->extentRemaining -= vars->bufferOffset;
945 if (!vars->extentRemaining)
946 {
947 vars->currentExtent++;
948 vars->extentRemaining = vars->currentExtent->length;
949 vars->extentPosition = vars->position;
950 if (!vars->extentRemaining)
951 {
952 err = kIOReturnOverrun;
953 break;
954 }
955 }
956
957 vars->bufferHalf = vars->bufferHalf ? 0 : vars->bufferSize;
958 vars->bufferOffset = 0;
959 if (vars->bufferSize <= vars->extentRemaining)
960 vars->bufferLimit = vars->bufferSize;
961 else
962 vars->bufferLimit = vars->extentRemaining;
963
964 flush = false;
965 }
966 }
967 while (size);
968
969 return (err);
970 }
971
972 static IOReturn
973 IOPolledFileRead(IOPolledFileIOVars * vars,
974 uint8_t * bytes, IOByteCount size,
975 hibernate_cryptvars_t * cryptvars)
976 {
977 IOReturn err = kIOReturnSuccess;
978 IOByteCount copy;
979
980 // bytesWritten += size;
981
982 do
983 {
984 copy = vars->bufferLimit - vars->bufferOffset;
985 if (copy > size)
986 copy = size;
987
988 if (bytes)
989 {
990 bcopy(vars->buffer + vars->bufferHalf + vars->bufferOffset, bytes, copy);
991 bytes += copy;
992 }
993 size -= copy;
994 vars->bufferOffset += copy;
995 // vars->position += copy;
996
997 if ((vars->bufferOffset == vars->bufferLimit) && (vars->position < vars->readEnd))
998 {
999 if (vars->io)
1000 {
1001 err = IOHibernatePollerIODone(vars, false);
1002 if (kIOReturnSuccess != err)
1003 break;
1004 }
1005 else
1006 cryptvars = 0;
1007
1008 if (vars->position & (vars->blockSize - 1)) HIBLOG("misaligned file pos %qx\n", vars->position);
1009
1010 vars->position += vars->lastRead;
1011 vars->extentRemaining -= vars->lastRead;
1012 vars->bufferLimit = vars->lastRead;
1013
1014 if (!vars->extentRemaining)
1015 {
1016 vars->currentExtent++;
1017 vars->extentRemaining = vars->currentExtent->length;
1018 vars->extentPosition = vars->position;
1019 if (!vars->extentRemaining)
1020 {
1021 err = kIOReturnOverrun;
1022 break;
1023 }
1024 }
1025
1026 uint64_t length;
1027 uint64_t lastReadLength = vars->lastRead;
1028 uint64_t offset = (vars->position
1029 - vars->extentPosition + vars->currentExtent->start);
1030 if (vars->extentRemaining <= vars->bufferSize)
1031 length = vars->extentRemaining;
1032 else
1033 length = vars->bufferSize;
1034 if ((length + vars->position) > vars->readEnd)
1035 length = vars->readEnd - vars->position;
1036
1037 vars->lastRead = length;
1038 if (length)
1039 {
1040 //if (length != vars->bufferSize) HIBLOG("short read of %qx ends@ %qx\n", length, offset + length);
1041 err = IOHibernatePollerIO(vars, kIOPolledRead, vars->bufferHalf, offset, length);
1042 if (kIOReturnSuccess != err)
1043 break;
1044 vars->io = true;
1045 }
1046
1047 vars->bufferHalf = vars->bufferHalf ? 0 : vars->bufferSize;
1048 vars->bufferOffset = 0;
1049
1050 #if CRYPTO
1051 if (cryptvars)
1052 {
1053 uint8_t thisVector[AES_BLOCK_SIZE];
1054 AbsoluteTime startTime, endTime;
1055
1056 // save initial vector for following decrypts
1057 bcopy(&cryptvars->aes_iv[0], &thisVector[0], AES_BLOCK_SIZE);
1058 bcopy(vars->buffer + vars->bufferHalf + lastReadLength - AES_BLOCK_SIZE,
1059 &cryptvars->aes_iv[0], AES_BLOCK_SIZE);
1060
1061 // decrypt the buffer
1062 clock_get_uptime(&startTime);
1063
1064 aes_decrypt_cbc(vars->buffer + vars->bufferHalf,
1065 &thisVector[0],
1066 lastReadLength / AES_BLOCK_SIZE,
1067 vars->buffer + vars->bufferHalf,
1068 &cryptvars->ctx.decrypt);
1069
1070 clock_get_uptime(&endTime);
1071 ADD_ABSOLUTETIME(&vars->cryptTime, &endTime);
1072 SUB_ABSOLUTETIME(&vars->cryptTime, &startTime);
1073 vars->cryptBytes += lastReadLength;
1074 }
1075 #endif /* CRYPTO */
1076 }
1077 }
1078 while (size);
1079
1080 return (err);
1081 }
1082
1083 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1084
1085 IOReturn
1086 IOHibernateSystemSleep(void)
1087 {
1088 IOReturn err;
1089 OSData * data;
1090 OSObject * obj;
1091 OSString * str;
1092 bool dsSSD;
1093
1094 IOHibernateVars * vars = &gIOHibernateVars;
1095
1096 if (vars->fileVars && vars->fileVars->fileRef)
1097 // already on the way down
1098 return (kIOReturnSuccess);
1099
1100 gIOHibernateState = kIOHibernateStateInactive;
1101
1102 gIOHibernateDebugFlags = 0;
1103 if (kIOLogHibernate & gIOKitDebug)
1104 gIOHibernateDebugFlags |= kIOHibernateDebugRestoreLogs;
1105
1106 if (IOService::getPMRootDomain()->getHibernateSettings(
1107 &gIOHibernateMode, &gIOHibernateFreeRatio, &gIOHibernateFreeTime))
1108 {
1109 if (kIOHibernateModeSleep & gIOHibernateMode)
1110 // default to discard clean for safe sleep
1111 gIOHibernateMode ^= (kIOHibernateModeDiscardCleanInactive
1112 | kIOHibernateModeDiscardCleanActive);
1113 }
1114
1115 if ((obj = IOService::getPMRootDomain()->copyProperty(kIOHibernateFileKey)))
1116 {
1117 if ((str = OSDynamicCast(OSString, obj)))
1118 strlcpy(gIOHibernateFilename, str->getCStringNoCopy(),
1119 sizeof(gIOHibernateFilename));
1120 obj->release();
1121 }
1122
1123 if (!gIOHibernateMode || !gIOHibernateFilename[0])
1124 return (kIOReturnUnsupported);
1125
1126 HIBLOG("hibernate image path: %s\n", gIOHibernateFilename);
1127
1128
1129 do
1130 {
1131 vars->srcBuffer = IOBufferMemoryDescriptor::withOptions(kIODirectionOutIn,
1132 4 * page_size, page_size);
1133 vars->ioBuffer = IOBufferMemoryDescriptor::withOptions(kIODirectionOutIn,
1134 2 * kDefaultIOSize, page_size);
1135
1136 vars->handoffBuffer = IOBufferMemoryDescriptor::withOptions(kIODirectionOutIn,
1137 ptoa_64(gIOHibernateHandoffPageCount), page_size);
1138
1139 if (!vars->srcBuffer || !vars->ioBuffer || !vars->handoffBuffer)
1140 {
1141 err = kIOReturnNoMemory;
1142 break;
1143 }
1144
1145 // open & invalidate the image file
1146 gIOHibernateCurrentHeader->signature = kIOHibernateHeaderInvalidSignature;
1147 err = IOPolledFileOpen(gIOHibernateFilename, vars->ioBuffer,
1148 &vars->fileVars, &vars->fileExtents, &data,
1149 &vars->volumeCryptKey[0]);
1150 if (KERN_SUCCESS != err)
1151 {
1152 HIBLOG("IOPolledFileOpen(%x)\n", err);
1153 break;
1154 }
1155
1156 bzero(gIOHibernateCurrentHeader, sizeof(IOHibernateImageHeader));
1157 gIOHibernateCurrentHeader->debugFlags = gIOHibernateDebugFlags;
1158 dsSSD = ((0 != (kIOHibernateOptionSSD & vars->fileVars->flags))
1159 && (kOSBooleanTrue == IOService::getPMRootDomain()->getProperty(kIOPMDeepSleepEnabledKey)));
1160 if (dsSSD)
1161 {
1162 gIOHibernateCurrentHeader->options |=
1163 kIOHibernateOptionSSD
1164 | kIOHibernateOptionColor;
1165
1166 #if defined(__i386__) || defined(__x86_64__)
1167 if (!uuid_is_null(vars->volumeCryptKey) &&
1168 (kOSBooleanTrue != IOService::getPMRootDomain()->getProperty(kIOPMDestroyFVKeyOnStandbyKey)))
1169 {
1170 uintptr_t smcVars[2];
1171 smcVars[0] = sizeof(vars->volumeCryptKey);
1172 smcVars[1] = (uintptr_t)(void *) &vars->volumeCryptKey[0];
1173
1174 IOService::getPMRootDomain()->setProperty(kIOHibernateSMCVariablesKey, smcVars, sizeof(smcVars));
1175 bzero(smcVars, sizeof(smcVars));
1176 }
1177 #endif
1178 }
1179 else
1180 {
1181 gIOHibernateCurrentHeader->options |= kIOHibernateOptionProgress;
1182 }
1183
1184 boolean_t encryptedswap;
1185 AbsoluteTime startTime, endTime;
1186 uint64_t nsec;
1187
1188 clock_get_uptime(&startTime);
1189 err = hibernate_setup(gIOHibernateCurrentHeader,
1190 gIOHibernateFreeRatio, gIOHibernateFreeTime,
1191 dsSSD,
1192 &vars->page_list, &vars->page_list_wired, &vars->page_list_pal, &encryptedswap);
1193 clock_get_uptime(&endTime);
1194 SUB_ABSOLUTETIME(&endTime, &startTime);
1195 absolutetime_to_nanoseconds(endTime, &nsec);
1196 HIBLOG("hibernate_setup(%d) took %qd ms\n", err, nsec / 1000000ULL);
1197
1198 if (KERN_SUCCESS != err)
1199 break;
1200
1201 if (encryptedswap || !uuid_is_null(vars->volumeCryptKey))
1202 gIOHibernateMode ^= kIOHibernateModeEncrypt;
1203
1204 if (kIOHibernateOptionProgress & gIOHibernateCurrentHeader->options)
1205 {
1206 vars->videoAllocSize = kVideoMapSize;
1207 if (KERN_SUCCESS != kmem_alloc_pageable(kernel_map, &vars->videoMapping, vars->videoAllocSize))
1208 vars->videoMapping = 0;
1209 }
1210
1211 // generate crypt keys
1212 for (uint32_t i = 0; i < sizeof(vars->wiredCryptKey); i++)
1213 vars->wiredCryptKey[i] = random();
1214 for (uint32_t i = 0; i < sizeof(vars->cryptKey); i++)
1215 vars->cryptKey[i] = random();
1216
1217 // set nvram
1218
1219 IORegistryEntry * regEntry;
1220 if (!gIOOptionsEntry)
1221 {
1222 regEntry = IORegistryEntry::fromPath("/options", gIODTPlane);
1223 gIOOptionsEntry = OSDynamicCast(IODTNVRAM, regEntry);
1224 if (regEntry && !gIOOptionsEntry)
1225 regEntry->release();
1226 }
1227 if (!gIOChosenEntry)
1228 gIOChosenEntry = IORegistryEntry::fromPath("/chosen", gIODTPlane);
1229
1230 if (gIOOptionsEntry)
1231 {
1232 const OSSymbol * sym;
1233
1234 sym = OSSymbol::withCStringNoCopy(kIOHibernateBootImageKey);
1235 if (sym)
1236 {
1237 gIOOptionsEntry->setProperty(sym, data);
1238 sym->release();
1239 }
1240 data->release();
1241
1242 #if defined(__i386__) || defined(__x86_64__)
1243 struct AppleRTCHibernateVars
1244 {
1245 uint8_t signature[4];
1246 uint32_t revision;
1247 uint8_t booterSignature[20];
1248 uint8_t wiredCryptKey[16];
1249 };
1250 AppleRTCHibernateVars rtcVars;
1251
1252 rtcVars.signature[0] = 'A';
1253 rtcVars.signature[1] = 'A';
1254 rtcVars.signature[2] = 'P';
1255 rtcVars.signature[3] = 'L';
1256 rtcVars.revision = 1;
1257 bcopy(&vars->wiredCryptKey[0], &rtcVars.wiredCryptKey[0], sizeof(rtcVars.wiredCryptKey));
1258 if (gIOHibernateBootSignature[0])
1259 {
1260 char c;
1261 uint8_t value = 0;
1262 for (uint32_t i = 0;
1263 (c = gIOHibernateBootSignature[i]) && (i < (sizeof(rtcVars.booterSignature) << 1));
1264 i++)
1265 {
1266 if (c >= 'a')
1267 c -= 'a' - 10;
1268 else if (c >= 'A')
1269 c -= 'A' - 10;
1270 else if (c >= '0')
1271 c -= '0';
1272 else
1273 continue;
1274 value = (value << 4) | c;
1275 if (i & 1)
1276 rtcVars.booterSignature[i >> 1] = value;
1277 }
1278 }
1279 data = OSData::withBytes(&rtcVars, sizeof(rtcVars));
1280 if (data)
1281 {
1282 if (!gIOHibernateRTCVariablesKey)
1283 gIOHibernateRTCVariablesKey = OSSymbol::withCStringNoCopy(kIOHibernateRTCVariablesKey);
1284 if (gIOHibernateRTCVariablesKey)
1285 IOService::getPMRootDomain()->setProperty(gIOHibernateRTCVariablesKey, data);
1286
1287 if( gIOOptionsEntry )
1288 {
1289 if( gIOHibernateMode & kIOHibernateModeSwitch )
1290 {
1291 const OSSymbol *sym;
1292 sym = OSSymbol::withCStringNoCopy(kIOHibernateBootSwitchVarsKey);
1293 if( sym )
1294 {
1295 gIOOptionsEntry->setProperty(sym, data); /* intentional insecure backup of rtc boot vars */
1296 sym->release();
1297 }
1298 }
1299 }
1300
1301 data->release();
1302 }
1303 if (gIOChosenEntry)
1304 {
1305 data = OSDynamicCast(OSData, gIOChosenEntry->getProperty(kIOHibernateMachineSignatureKey));
1306 if (data)
1307 gIOHibernateCurrentHeader->machineSignature = *((UInt32 *)data->getBytesNoCopy());
1308 {
1309 // set BootNext
1310
1311 if (!gIOHibernateBoot0082Data)
1312 {
1313 data = OSDynamicCast(OSData, gIOChosenEntry->getProperty("boot-device-path"));
1314 if (data)
1315 {
1316 // AppleNVRAM_EFI_LOAD_OPTION
1317 struct {
1318 uint32_t Attributes;
1319 uint16_t FilePathLength;
1320 uint16_t Desc;
1321 } loadOptionHeader;
1322 loadOptionHeader.Attributes = 1;
1323 loadOptionHeader.FilePathLength = data->getLength();
1324 loadOptionHeader.Desc = 0;
1325 gIOHibernateBoot0082Data = OSData::withCapacity(sizeof(loadOptionHeader) + loadOptionHeader.FilePathLength);
1326 if (gIOHibernateBoot0082Data)
1327 {
1328 gIOHibernateBoot0082Data->appendBytes(&loadOptionHeader, sizeof(loadOptionHeader));
1329 gIOHibernateBoot0082Data->appendBytes(data);
1330 }
1331 }
1332 }
1333 if (!gIOHibernateBoot0082Key)
1334 gIOHibernateBoot0082Key = OSSymbol::withCString("8BE4DF61-93CA-11D2-AA0D-00E098032B8C:Boot0082");
1335 if (!gIOHibernateBootNextKey)
1336 gIOHibernateBootNextKey = OSSymbol::withCString("8BE4DF61-93CA-11D2-AA0D-00E098032B8C:BootNext");
1337 if (!gIOHibernateBootNextData)
1338 {
1339 uint16_t bits = 0x0082;
1340 gIOHibernateBootNextData = OSData::withBytes(&bits, sizeof(bits));
1341 }
1342 if (gIOHibernateBoot0082Key && gIOHibernateBoot0082Data && gIOHibernateBootNextKey && gIOHibernateBootNextData)
1343 {
1344 gIOHibernateBootNextSave = gIOOptionsEntry->copyProperty(gIOHibernateBootNextKey);
1345 gIOOptionsEntry->setProperty(gIOHibernateBoot0082Key, gIOHibernateBoot0082Data);
1346 gIOOptionsEntry->setProperty(gIOHibernateBootNextKey, gIOHibernateBootNextData);
1347 }
1348 }
1349 }
1350 #else /* !i386 && !x86_64 */
1351 if (kIOHibernateModeEncrypt & gIOHibernateMode)
1352 {
1353 data = OSData::withBytes(&vars->wiredCryptKey[0], sizeof(vars->wiredCryptKey));
1354 sym = OSSymbol::withCStringNoCopy(kIOHibernateBootImageKeyKey);
1355 if (sym && data)
1356 gIOOptionsEntry->setProperty(sym, data);
1357 if (sym)
1358 sym->release();
1359 if (data)
1360 data->release();
1361 if (false && gIOHibernateBootSignature[0])
1362 {
1363 data = OSData::withCapacity(16);
1364 sym = OSSymbol::withCStringNoCopy(kIOHibernateBootSignatureKey);
1365 if (sym && data)
1366 {
1367 char c;
1368 uint8_t value = 0;
1369 for (uint32_t i = 0; (c = gIOHibernateBootSignature[i]); i++)
1370 {
1371 if (c >= 'a')
1372 c -= 'a' - 10;
1373 else if (c >= 'A')
1374 c -= 'A' - 10;
1375 else if (c >= '0')
1376 c -= '0';
1377 else
1378 continue;
1379 value = (value << 4) | c;
1380 if (i & 1)
1381 data->appendBytes(&value, sizeof(value));
1382 }
1383 gIOOptionsEntry->setProperty(sym, data);
1384 }
1385 if (sym)
1386 sym->release();
1387 if (data)
1388 data->release();
1389 }
1390 }
1391 if (!vars->haveFastBoot)
1392 {
1393 // set boot volume to zero
1394 IODTPlatformExpert * platform = OSDynamicCast(IODTPlatformExpert, IOService::getPlatform());
1395 if (platform && (kIOReturnSuccess == platform->readXPRAM(kXPRamAudioVolume,
1396 &vars->saveBootAudioVolume, sizeof(vars->saveBootAudioVolume))))
1397 {
1398 uint8_t newVolume;
1399 newVolume = vars->saveBootAudioVolume & 0xf8;
1400 platform->writeXPRAM(kXPRamAudioVolume,
1401 &newVolume, sizeof(newVolume));
1402 }
1403 }
1404 #endif /* !i386 && !x86_64 */
1405 }
1406 // --
1407
1408 gIOHibernateCurrentHeader->signature = kIOHibernateHeaderSignature;
1409 gIOHibernateState = kIOHibernateStateHibernating;
1410 }
1411 while (false);
1412
1413 return (err);
1414 }
1415
1416 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1417
1418 DECLARE_IOHIBERNATEPROGRESSALPHA
1419
1420 static void
1421 ProgressInit(hibernate_graphics_t * display, uint8_t * screen, uint8_t * saveunder, uint32_t savelen)
1422 {
1423 uint32_t rowBytes, pixelShift;
1424 uint32_t x, y;
1425 int32_t blob;
1426 uint32_t alpha, in, color, result;
1427 uint8_t * out;
1428 uint32_t saveindex[kIOHibernateProgressCount] = { 0 };
1429
1430 rowBytes = display->rowBytes;
1431 pixelShift = display->depth >> 4;
1432 if (pixelShift < 1) return;
1433
1434 screen += ((display->width
1435 - kIOHibernateProgressCount * (kIOHibernateProgressWidth + kIOHibernateProgressSpacing)) << (pixelShift - 1))
1436 + (display->height - kIOHibernateProgressOriginY - kIOHibernateProgressHeight) * rowBytes;
1437
1438 for (y = 0; y < kIOHibernateProgressHeight; y++)
1439 {
1440 out = screen + y * rowBytes;
1441 for (blob = 0; blob < kIOHibernateProgressCount; blob++)
1442 {
1443 color = blob ? kIOHibernateProgressDarkGray : kIOHibernateProgressMidGray;
1444 for (x = 0; x < kIOHibernateProgressWidth; x++)
1445 {
1446 alpha = gIOHibernateProgressAlpha[y][x];
1447 result = color;
1448 if (alpha)
1449 {
1450 if (0xff != alpha)
1451 {
1452 if (1 == pixelShift)
1453 {
1454 in = *((uint16_t *)out) & 0x1f; // 16
1455 in = (in << 3) | (in >> 2);
1456 }
1457 else
1458 in = *((uint32_t *)out) & 0xff; // 32
1459 saveunder[blob * kIOHibernateProgressSaveUnderSize + saveindex[blob]++] = in;
1460 result = ((255 - alpha) * in + alpha * result + 0xff) >> 8;
1461 }
1462 if (1 == pixelShift)
1463 {
1464 result >>= 3;
1465 *((uint16_t *)out) = (result << 10) | (result << 5) | result; // 16
1466 }
1467 else
1468 *((uint32_t *)out) = (result << 16) | (result << 8) | result; // 32
1469 }
1470 out += (1 << pixelShift);
1471 }
1472 out += (kIOHibernateProgressSpacing << pixelShift);
1473 }
1474 }
1475 }
1476
1477
1478 static void
1479 ProgressUpdate(hibernate_graphics_t * display, uint8_t * screen, int32_t firstBlob, int32_t select)
1480 {
1481 uint32_t rowBytes, pixelShift;
1482 uint32_t x, y;
1483 int32_t blob, lastBlob;
1484 uint32_t alpha, in, color, result;
1485 uint8_t * out;
1486 uint32_t saveindex[kIOHibernateProgressCount] = { 0 };
1487
1488 pixelShift = display->depth >> 4;
1489 if (pixelShift < 1)
1490 return;
1491
1492 rowBytes = display->rowBytes;
1493
1494 screen += ((display->width
1495 - kIOHibernateProgressCount * (kIOHibernateProgressWidth + kIOHibernateProgressSpacing)) << (pixelShift - 1))
1496 + (display->height - kIOHibernateProgressOriginY - kIOHibernateProgressHeight) * rowBytes;
1497
1498 lastBlob = (select < kIOHibernateProgressCount) ? select : (kIOHibernateProgressCount - 1);
1499
1500 screen += (firstBlob * (kIOHibernateProgressWidth + kIOHibernateProgressSpacing)) << pixelShift;
1501
1502 for (y = 0; y < kIOHibernateProgressHeight; y++)
1503 {
1504 out = screen + y * rowBytes;
1505 for (blob = firstBlob; blob <= lastBlob; blob++)
1506 {
1507 color = (blob < select) ? kIOHibernateProgressLightGray : kIOHibernateProgressMidGray;
1508 for (x = 0; x < kIOHibernateProgressWidth; x++)
1509 {
1510 alpha = gIOHibernateProgressAlpha[y][x];
1511 result = color;
1512 if (alpha)
1513 {
1514 if (0xff != alpha)
1515 {
1516 in = display->progressSaveUnder[blob][saveindex[blob]++];
1517 result = ((255 - alpha) * in + alpha * result + 0xff) / 255;
1518 }
1519 if (1 == pixelShift)
1520 {
1521 result >>= 3;
1522 *((uint16_t *)out) = (result << 10) | (result << 5) | result; // 16
1523 }
1524 else
1525 *((uint32_t *)out) = (result << 16) | (result << 8) | result; // 32
1526 }
1527 out += (1 << pixelShift);
1528 }
1529 out += (kIOHibernateProgressSpacing << pixelShift);
1530 }
1531 }
1532 }
1533
1534 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1535
1536 IOReturn
1537 IOHibernateSystemHasSlept(void)
1538 {
1539 IOHibernateVars * vars = &gIOHibernateVars;
1540 OSObject * obj;
1541 OSData * data;
1542
1543 obj = IOService::getPMRootDomain()->copyProperty(kIOHibernatePreviewBufferKey);
1544 vars->previewBuffer = OSDynamicCast(IOMemoryDescriptor, obj);
1545 if (obj && !vars->previewBuffer)
1546 obj->release();
1547
1548 vars->consoleMapping = NULL;
1549 if (vars->previewBuffer && (kIOReturnSuccess != vars->previewBuffer->prepare()))
1550 {
1551 vars->previewBuffer->release();
1552 vars->previewBuffer = 0;
1553 }
1554
1555 if ((kIOHibernateOptionProgress & gIOHibernateCurrentHeader->options)
1556 && vars->previewBuffer
1557 && (data = OSDynamicCast(OSData,
1558 IOService::getPMRootDomain()->getProperty(kIOHibernatePreviewActiveKey))))
1559 {
1560 UInt32 flags = *((UInt32 *)data->getBytesNoCopy());
1561 HIBPRINT("kIOHibernatePreviewActiveKey %08lx\n", (long)flags);
1562
1563 IOService::getPMRootDomain()->removeProperty(kIOHibernatePreviewActiveKey);
1564
1565 if (kIOHibernatePreviewUpdates & flags)
1566 {
1567 PE_Video consoleInfo;
1568 hibernate_graphics_t * graphicsInfo = gIOHibernateGraphicsInfo;
1569
1570 IOService::getPlatform()->getConsoleInfo(&consoleInfo);
1571
1572 graphicsInfo->width = consoleInfo.v_width;
1573 graphicsInfo->height = consoleInfo.v_height;
1574 graphicsInfo->rowBytes = consoleInfo.v_rowBytes;
1575 graphicsInfo->depth = consoleInfo.v_depth;
1576 vars->consoleMapping = (uint8_t *) consoleInfo.v_baseAddr;
1577
1578 HIBPRINT("video %p %d %d %d\n",
1579 vars->consoleMapping, graphicsInfo->depth,
1580 graphicsInfo->width, graphicsInfo->height);
1581 if (vars->consoleMapping)
1582 ProgressInit(graphicsInfo, vars->consoleMapping,
1583 &graphicsInfo->progressSaveUnder[0][0], sizeof(graphicsInfo->progressSaveUnder));
1584 }
1585 }
1586
1587 if (gIOOptionsEntry)
1588 gIOOptionsEntry->sync();
1589
1590 return (kIOReturnSuccess);
1591 }
1592
1593 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1594
1595 static DeviceTreeNode *
1596 MergeDeviceTree(DeviceTreeNode * entry, IORegistryEntry * regEntry)
1597 {
1598 DeviceTreeNodeProperty * prop;
1599 DeviceTreeNode * child;
1600 IORegistryEntry * childRegEntry;
1601 const char * nameProp;
1602 unsigned int propLen, idx;
1603
1604 prop = (DeviceTreeNodeProperty *) (entry + 1);
1605 for (idx = 0; idx < entry->nProperties; idx++)
1606 {
1607 if (regEntry && (0 != strcmp("name", prop->name)))
1608 {
1609 regEntry->setProperty((const char *) prop->name, (void *) (prop + 1), prop->length);
1610 // HIBPRINT("%s: %s, %d\n", regEntry->getName(), prop->name, prop->length);
1611 }
1612 prop = (DeviceTreeNodeProperty *) (((uintptr_t)(prop + 1)) + ((prop->length + 3) & ~3));
1613 }
1614
1615 child = (DeviceTreeNode *) prop;
1616 for (idx = 0; idx < entry->nChildren; idx++)
1617 {
1618 if (kSuccess != DTGetProperty(child, "name", (void **) &nameProp, &propLen))
1619 panic("no name");
1620 childRegEntry = regEntry ? regEntry->childFromPath(nameProp, gIODTPlane) : NULL;
1621 // HIBPRINT("%s == %p\n", nameProp, childRegEntry);
1622 child = MergeDeviceTree(child, childRegEntry);
1623 }
1624 return (child);
1625 }
1626
1627 IOReturn
1628 IOHibernateSystemWake(void)
1629 {
1630 IOHibernateVars * vars = &gIOHibernateVars;
1631
1632 hibernate_teardown(vars->page_list, vars->page_list_wired);
1633
1634 if (vars->videoMapping)
1635 {
1636 if (vars->videoMapSize)
1637 // remove mappings
1638 IOUnmapPages(kernel_map, vars->videoMapping, vars->videoMapSize);
1639 if (vars->videoAllocSize)
1640 // dealloc range
1641 kmem_free(kernel_map, trunc_page(vars->videoMapping), vars->videoAllocSize);
1642 }
1643
1644 if (vars->previewBuffer)
1645 {
1646 vars->previewBuffer->release();
1647 vars->previewBuffer = 0;
1648 }
1649
1650 if (kIOHibernateStateWakingFromHibernate == gIOHibernateState)
1651 {
1652 IOService::getPMRootDomain()->setProperty(kIOHibernateOptionsKey,
1653 gIOHibernateCurrentHeader->options, 32);
1654 }
1655 else
1656 {
1657 IOService::getPMRootDomain()->removeProperty(kIOHibernateOptionsKey);
1658 }
1659
1660 if ((kIOHibernateStateWakingFromHibernate == gIOHibernateState)
1661 && (kIOHibernateGfxStatusUnknown != gIOHibernateGraphicsInfo->gfxStatus))
1662 {
1663 IOService::getPMRootDomain()->setProperty(kIOHibernateGfxStatusKey,
1664 &gIOHibernateGraphicsInfo->gfxStatus,
1665 sizeof(gIOHibernateGraphicsInfo->gfxStatus));
1666 }
1667 else
1668 {
1669 IOService::getPMRootDomain()->removeProperty(kIOHibernateGfxStatusKey);
1670 }
1671
1672
1673 if (vars->fileVars)
1674 {
1675 IOPolledFileClose(vars->fileVars);
1676 }
1677
1678 // invalidate nvram properties - (gIOOptionsEntry != 0) => nvram was touched
1679
1680 #if defined(__i386__) || defined(__x86_64__)
1681 IOService::getPMRootDomain()->removeProperty(gIOHibernateRTCVariablesKey);
1682 IOService::getPMRootDomain()->removeProperty(kIOHibernateSMCVariablesKey);
1683
1684 /*
1685 * Hibernate variable is written to NVRAM on platforms in which RtcRam
1686 * is not backed by coin cell. Remove Hibernate data from NVRAM.
1687 */
1688 if (gIOOptionsEntry) {
1689
1690 if (gIOHibernateRTCVariablesKey) {
1691 if (gIOOptionsEntry->getProperty(gIOHibernateRTCVariablesKey)) {
1692 gIOOptionsEntry->removeProperty(gIOHibernateRTCVariablesKey);
1693 }
1694 }
1695
1696 if (gIOHibernateBootNextKey)
1697 {
1698 if (gIOHibernateBootNextSave)
1699 {
1700 gIOOptionsEntry->setProperty(gIOHibernateBootNextKey, gIOHibernateBootNextSave);
1701 gIOHibernateBootNextSave->release();
1702 gIOHibernateBootNextSave = NULL;
1703 }
1704 else
1705 gIOOptionsEntry->removeProperty(gIOHibernateBootNextKey);
1706 }
1707 gIOOptionsEntry->sync();
1708 }
1709 #endif
1710
1711 if (vars->srcBuffer)
1712 vars->srcBuffer->release();
1713 if (vars->ioBuffer)
1714 vars->ioBuffer->release();
1715 bzero(&gIOHibernateHandoffPages[0], gIOHibernateHandoffPageCount * sizeof(gIOHibernateHandoffPages[0]));
1716 if (vars->handoffBuffer)
1717 {
1718 IOHibernateHandoff * handoff;
1719 bool done = false;
1720 for (handoff = (IOHibernateHandoff *) vars->handoffBuffer->getBytesNoCopy();
1721 !done;
1722 handoff = (IOHibernateHandoff *) &handoff->data[handoff->bytecount])
1723 {
1724 // HIBPRINT("handoff %p, %x, %x\n", handoff, handoff->type, handoff->bytecount);
1725 uint8_t * data = &handoff->data[0];
1726 switch (handoff->type)
1727 {
1728 case kIOHibernateHandoffTypeEnd:
1729 done = true;
1730 break;
1731
1732 case kIOHibernateHandoffTypeDeviceTree:
1733 MergeDeviceTree((DeviceTreeNode *) data, IOService::getServiceRoot());
1734 break;
1735
1736 case kIOHibernateHandoffTypeKeyStore:
1737 #if defined(__i386__) || defined(__x86_64__)
1738 {
1739 IOBufferMemoryDescriptor *
1740 md = IOBufferMemoryDescriptor::withBytes(data, handoff->bytecount, kIODirectionOutIn);
1741 if (md)
1742 {
1743 IOSetKeyStoreData(md);
1744 }
1745 }
1746 #endif
1747 break;
1748
1749 default:
1750 done = (kIOHibernateHandoffType != (handoff->type & 0xFFFF0000));
1751 break;
1752 }
1753 }
1754 vars->handoffBuffer->release();
1755 }
1756 if (vars->fileExtents)
1757 vars->fileExtents->release();
1758
1759 bzero(vars, sizeof(*vars));
1760
1761 // gIOHibernateState = kIOHibernateStateInactive; // leave it for post wake code to see
1762
1763 return (kIOReturnSuccess);
1764 }
1765
1766 IOReturn
1767 IOHibernateSystemPostWake(void)
1768 {
1769 if (gIOHibernateFileRef)
1770 {
1771 // invalidate & close the image file
1772 gIOHibernateCurrentHeader->signature = kIOHibernateHeaderInvalidSignature;
1773 kern_close_file_for_direct_io(gIOHibernateFileRef,
1774 0, (caddr_t) gIOHibernateCurrentHeader,
1775 sizeof(IOHibernateImageHeader));
1776 gIOHibernateFileRef = 0;
1777 }
1778 return (kIOReturnSuccess);
1779 }
1780
1781 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1782
1783 SYSCTL_STRING(_kern, OID_AUTO, hibernatefile,
1784 CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
1785 gIOHibernateFilename, sizeof(gIOHibernateFilename), "");
1786 SYSCTL_STRING(_kern, OID_AUTO, bootsignature,
1787 CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
1788 gIOHibernateBootSignature, sizeof(gIOHibernateBootSignature), "");
1789 SYSCTL_UINT(_kern, OID_AUTO, hibernatemode,
1790 CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
1791 &gIOHibernateMode, 0, "");
1792
1793 void
1794 IOHibernateSystemInit(IOPMrootDomain * rootDomain)
1795 {
1796 OSData * data = OSData::withBytesNoCopy(&gIOHibernateState, sizeof(gIOHibernateState));
1797 if (data)
1798 {
1799 rootDomain->setProperty(kIOHibernateStateKey, data);
1800 data->release();
1801 }
1802
1803 if (PE_parse_boot_argn("hfile", gIOHibernateFilename, sizeof(gIOHibernateFilename)))
1804 gIOHibernateMode = kIOHibernateModeOn;
1805 else
1806 gIOHibernateFilename[0] = 0;
1807
1808 sysctl_register_oid(&sysctl__kern_hibernatefile);
1809 sysctl_register_oid(&sysctl__kern_bootsignature);
1810 sysctl_register_oid(&sysctl__kern_hibernatemode);
1811 }
1812
1813
1814 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1815
1816 static void
1817 hibernate_setup_for_wake(void)
1818 {
1819 }
1820
1821 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1822
1823 #define C_ASSERT(e) typedef char __C_ASSERT__[(e) ? 1 : -1]
1824
1825 static bool
1826 no_encrypt_page(vm_offset_t ppnum)
1827 {
1828 if (pmap_is_noencrypt((ppnum_t)ppnum) == TRUE)
1829 {
1830 return true;
1831 }
1832 return false;
1833 }
1834
1835 uint32_t wired_pages_encrypted = 0;
1836 uint32_t dirty_pages_encrypted = 0;
1837 uint32_t wired_pages_clear = 0;
1838
1839 static void
1840 hibernate_pal_callback(void *vars_arg, vm_offset_t addr)
1841 {
1842 IOHibernateVars *vars = (IOHibernateVars *)vars_arg;
1843 /* Make sure it's not in either of the save lists */
1844 hibernate_set_page_state(vars->page_list, vars->page_list_wired, atop_64(addr), 1, kIOHibernatePageStateFree);
1845
1846 /* Set it in the bitmap of pages owned by the PAL */
1847 hibernate_page_bitset(vars->page_list_pal, TRUE, atop_64(addr));
1848 }
1849
1850 static struct hibernate_cryptvars_t *local_cryptvars;
1851
1852 extern "C" int
1853 hibernate_pal_write(void *buffer, size_t size)
1854 {
1855 IOHibernateVars * vars = &gIOHibernateVars;
1856
1857 IOReturn err = IOPolledFileWrite(vars->fileVars, (const uint8_t *)buffer, size, local_cryptvars);
1858 if (kIOReturnSuccess != err) {
1859 kprintf("epic hibernate fail! %d\n", err);
1860 return err;
1861 }
1862
1863 return 0;
1864 }
1865
1866
1867 extern "C" uint32_t
1868 hibernate_write_image(void)
1869 {
1870 IOHibernateImageHeader * header = gIOHibernateCurrentHeader;
1871 IOHibernateVars * vars = &gIOHibernateVars;
1872 IOPolledFileExtent * fileExtents;
1873
1874 C_ASSERT(sizeof(IOHibernateImageHeader) == 512);
1875
1876 uint32_t pageCount, pagesDone;
1877 IOReturn err;
1878 vm_offset_t ppnum, page;
1879 IOItemCount count;
1880 uint8_t * src;
1881 uint8_t * data;
1882 IOByteCount pageCompressedSize;
1883 uint64_t compressedSize, uncompressedSize;
1884 uint64_t image1Size = 0;
1885 uint32_t bitmap_size;
1886 bool iterDone, pollerOpen, needEncrypt;
1887 uint32_t restore1Sum, sum, sum1, sum2;
1888 uint32_t tag;
1889 uint32_t pageType;
1890 uint32_t pageAndCount[2];
1891 addr64_t phys64;
1892 IOByteCount segLen;
1893
1894 AbsoluteTime startTime, endTime;
1895 AbsoluteTime allTime, compTime;
1896 uint64_t compBytes;
1897 uint64_t nsec;
1898 uint32_t lastProgressStamp = 0;
1899 uint32_t progressStamp;
1900 uint32_t blob, lastBlob = (uint32_t) -1L;
1901
1902 hibernate_cryptvars_t _cryptvars;
1903 hibernate_cryptvars_t * cryptvars = 0;
1904
1905 wired_pages_encrypted = 0;
1906 dirty_pages_encrypted = 0;
1907 wired_pages_clear = 0;
1908
1909 if (!vars->fileVars || !vars->fileVars->pollers || !vars->fileExtents)
1910 return (false /* sleep */ );
1911
1912 if (kIOHibernateModeSleep & gIOHibernateMode)
1913 kdebug_enable = save_kdebug_enable;
1914
1915 KERNEL_DEBUG_CONSTANT(IOKDBG_CODE(DBG_HIBERNATE, 1) | DBG_FUNC_START, 0, 0, 0, 0, 0);
1916 IOService::getPMRootDomain()->tracePoint(kIOPMTracePointHibernate);
1917
1918 restore1Sum = sum1 = sum2 = 0;
1919
1920 hibernate_pal_prepare();
1921
1922 #if CRYPTO
1923 // encryption data. "iv" is the "initial vector".
1924 if (kIOHibernateModeEncrypt & gIOHibernateMode)
1925 {
1926 static const unsigned char first_iv[AES_BLOCK_SIZE]
1927 = { 0xa3, 0x63, 0x65, 0xa9, 0x0b, 0x71, 0x7b, 0x1c,
1928 0xdf, 0x9e, 0x5f, 0x32, 0xd7, 0x61, 0x63, 0xda };
1929
1930 cryptvars = &gIOHibernateCryptWakeContext;
1931 bzero(cryptvars, sizeof(hibernate_cryptvars_t));
1932 aes_encrypt_key(vars->cryptKey,
1933 kIOHibernateAESKeySize,
1934 &cryptvars->ctx.encrypt);
1935 aes_decrypt_key(vars->cryptKey,
1936 kIOHibernateAESKeySize,
1937 &cryptvars->ctx.decrypt);
1938
1939 cryptvars = &_cryptvars;
1940 bzero(cryptvars, sizeof(hibernate_cryptvars_t));
1941 for (pageCount = 0; pageCount < sizeof(vars->wiredCryptKey); pageCount++)
1942 vars->wiredCryptKey[pageCount] ^= vars->volumeCryptKey[pageCount];
1943 bzero(&vars->volumeCryptKey[0], sizeof(vars->volumeCryptKey));
1944 aes_encrypt_key(vars->wiredCryptKey,
1945 kIOHibernateAESKeySize,
1946 &cryptvars->ctx.encrypt);
1947
1948 bcopy(&first_iv[0], &cryptvars->aes_iv[0], AES_BLOCK_SIZE);
1949 bzero(&vars->wiredCryptKey[0], sizeof(vars->wiredCryptKey));
1950 bzero(&vars->cryptKey[0], sizeof(vars->cryptKey));
1951
1952 local_cryptvars = cryptvars;
1953 }
1954 #endif /* CRYPTO */
1955
1956 hibernate_setup_for_wake();
1957
1958 hibernate_page_list_setall(vars->page_list,
1959 vars->page_list_wired,
1960 vars->page_list_pal,
1961 &pageCount);
1962
1963 HIBLOG("hibernate_page_list_setall found pageCount %d\n", pageCount);
1964
1965 fileExtents = (IOPolledFileExtent *) vars->fileExtents->getBytesNoCopy();
1966
1967 #if 0
1968 count = vars->fileExtents->getLength() / sizeof(IOPolledFileExtent);
1969 for (page = 0; page < count; page++)
1970 {
1971 HIBLOG("fileExtents[%d] %qx, %qx (%qx)\n", page,
1972 fileExtents[page].start, fileExtents[page].length,
1973 fileExtents[page].start + fileExtents[page].length);
1974 }
1975 #endif
1976
1977 needEncrypt = (0 != (kIOHibernateModeEncrypt & gIOHibernateMode));
1978 AbsoluteTime_to_scalar(&compTime) = 0;
1979 compBytes = 0;
1980
1981 clock_get_uptime(&allTime);
1982 IOService::getPMRootDomain()->pmStatsRecordEvent(
1983 kIOPMStatsHibernateImageWrite | kIOPMStatsEventStartFlag, allTime);
1984
1985 do
1986 {
1987 compressedSize = 0;
1988 uncompressedSize = 0;
1989
1990 IOPolledFileSeek(vars->fileVars, sizeof(IOHibernateImageHeader));
1991
1992 HIBLOG("IOHibernatePollerOpen, ml_get_interrupts_enabled %d\n",
1993 ml_get_interrupts_enabled());
1994 err = IOHibernatePollerOpen(vars->fileVars, kIOPolledBeforeSleepState, vars->ioBuffer);
1995 HIBLOG("IOHibernatePollerOpen(%x)\n", err);
1996 pollerOpen = (kIOReturnSuccess == err);
1997 if (!pollerOpen)
1998 break;
1999
2000 // copy file block extent list if larger than header
2001
2002 count = vars->fileExtents->getLength();
2003 if (count > sizeof(header->fileExtentMap))
2004 {
2005 count -= sizeof(header->fileExtentMap);
2006 err = IOPolledFileWrite(vars->fileVars,
2007 ((uint8_t *) &fileExtents[0]) + sizeof(header->fileExtentMap), count, cryptvars);
2008 if (kIOReturnSuccess != err)
2009 break;
2010 }
2011
2012 uintptr_t hibernateBase;
2013 uintptr_t hibernateEnd;
2014
2015 hibernateBase = HIB_BASE; /* Defined in PAL headers */
2016
2017 hibernateEnd = (sectHIBB + sectSizeHIB);
2018
2019 // copy out restore1 code
2020
2021 for (count = 0;
2022 (phys64 = vars->handoffBuffer->getPhysicalSegment(count, &segLen, kIOMemoryMapperNone));
2023 count += segLen)
2024 {
2025 for (pagesDone = 0; pagesDone < atop_32(segLen); pagesDone++)
2026 {
2027 gIOHibernateHandoffPages[atop_32(count) + pagesDone] = atop_64(phys64) + pagesDone;
2028 }
2029 }
2030
2031 page = atop_32(kvtophys(hibernateBase));
2032 count = atop_32(round_page(hibernateEnd) - hibernateBase);
2033 header->restore1CodePhysPage = page;
2034 header->restore1CodeVirt = hibernateBase;
2035 header->restore1PageCount = count;
2036 header->restore1CodeOffset = ((uintptr_t) &hibernate_machine_entrypoint) - hibernateBase;
2037 header->restore1StackOffset = ((uintptr_t) &gIOHibernateRestoreStackEnd[0]) - 64 - hibernateBase;
2038
2039 // sum __HIB sect, with zeros for the stack
2040 src = (uint8_t *) trunc_page(hibernateBase);
2041 for (page = 0; page < count; page++)
2042 {
2043 if ((src < &gIOHibernateRestoreStack[0]) || (src >= &gIOHibernateRestoreStackEnd[0]))
2044 restore1Sum += hibernate_sum_page(src, header->restore1CodeVirt + page);
2045 else
2046 restore1Sum += 0x00000000;
2047 src += page_size;
2048 }
2049 sum1 = restore1Sum;
2050
2051 // write the __HIB sect, with zeros for the stack
2052
2053 src = (uint8_t *) trunc_page(hibernateBase);
2054 count = ((uintptr_t) &gIOHibernateRestoreStack[0]) - trunc_page(hibernateBase);
2055 if (count)
2056 {
2057 err = IOPolledFileWrite(vars->fileVars, src, count, cryptvars);
2058 if (kIOReturnSuccess != err)
2059 break;
2060 }
2061 err = IOPolledFileWrite(vars->fileVars,
2062 (uint8_t *) 0,
2063 &gIOHibernateRestoreStackEnd[0] - &gIOHibernateRestoreStack[0],
2064 cryptvars);
2065 if (kIOReturnSuccess != err)
2066 break;
2067 src = &gIOHibernateRestoreStackEnd[0];
2068 count = round_page(hibernateEnd) - ((uintptr_t) src);
2069 if (count)
2070 {
2071 err = IOPolledFileWrite(vars->fileVars, src, count, cryptvars);
2072 if (kIOReturnSuccess != err)
2073 break;
2074 }
2075
2076 // write the preview buffer
2077
2078 if (vars->previewBuffer)
2079 {
2080 ppnum = 0;
2081 count = 0;
2082 do
2083 {
2084 phys64 = vars->previewBuffer->getPhysicalSegment(count, &segLen, kIOMemoryMapperNone);
2085 pageAndCount[0] = atop_64(phys64);
2086 pageAndCount[1] = atop_32(segLen);
2087 err = IOPolledFileWrite(vars->fileVars,
2088 (const uint8_t *) &pageAndCount, sizeof(pageAndCount),
2089 cryptvars);
2090 if (kIOReturnSuccess != err)
2091 break;
2092 count += segLen;
2093 ppnum += sizeof(pageAndCount);
2094 }
2095 while (phys64);
2096 if (kIOReturnSuccess != err)
2097 break;
2098
2099 src = (uint8_t *) vars->previewBuffer->getPhysicalSegment(0, NULL, _kIOMemorySourceSegment);
2100 count = vars->previewBuffer->getLength();
2101
2102 header->previewPageListSize = ppnum;
2103 header->previewSize = count + ppnum;
2104
2105 for (page = 0; page < count; page += page_size)
2106 {
2107 phys64 = vars->previewBuffer->getPhysicalSegment(page, NULL, kIOMemoryMapperNone);
2108 sum1 += hibernate_sum_page(src + page, atop_64(phys64));
2109 }
2110 err = IOPolledFileWrite(vars->fileVars, src, count, cryptvars);
2111 if (kIOReturnSuccess != err)
2112 break;
2113 }
2114
2115 // mark areas for no save
2116
2117 for (count = 0;
2118 (phys64 = vars->ioBuffer->getPhysicalSegment(count, &segLen, kIOMemoryMapperNone));
2119 count += segLen)
2120 {
2121 hibernate_set_page_state(vars->page_list, vars->page_list_wired,
2122 atop_64(phys64), atop_32(segLen),
2123 kIOHibernatePageStateFree);
2124 pageCount -= atop_32(segLen);
2125 }
2126
2127 for (count = 0;
2128 (phys64 = vars->srcBuffer->getPhysicalSegment(count, &segLen, kIOMemoryMapperNone));
2129 count += segLen)
2130 {
2131 hibernate_set_page_state(vars->page_list, vars->page_list_wired,
2132 atop_64(phys64), atop_32(segLen),
2133 kIOHibernatePageStateFree);
2134 pageCount -= atop_32(segLen);
2135 }
2136
2137 // copy out bitmap of pages available for trashing during restore
2138
2139 bitmap_size = vars->page_list_wired->list_size;
2140 src = (uint8_t *) vars->page_list_wired;
2141 err = IOPolledFileWrite(vars->fileVars, src, bitmap_size, cryptvars);
2142 if (kIOReturnSuccess != err)
2143 break;
2144
2145 // mark more areas for no save, but these are not available
2146 // for trashing during restore
2147
2148 hibernate_page_list_set_volatile(vars->page_list, vars->page_list_wired, &pageCount);
2149
2150
2151 page = atop_32(KERNEL_IMAGE_TO_PHYS(hibernateBase));
2152 count = atop_32(round_page(KERNEL_IMAGE_TO_PHYS(hibernateEnd))) - page;
2153 hibernate_set_page_state(vars->page_list, vars->page_list_wired,
2154 page, count,
2155 kIOHibernatePageStateFree);
2156 pageCount -= count;
2157
2158 if (vars->previewBuffer) for (count = 0;
2159 (phys64 = vars->previewBuffer->getPhysicalSegment(count, &segLen, kIOMemoryMapperNone));
2160 count += segLen)
2161 {
2162 hibernate_set_page_state(vars->page_list, vars->page_list_wired,
2163 atop_64(phys64), atop_32(segLen),
2164 kIOHibernatePageStateFree);
2165 pageCount -= atop_32(segLen);
2166 }
2167
2168 for (count = 0;
2169 (phys64 = vars->handoffBuffer->getPhysicalSegment(count, &segLen, kIOMemoryMapperNone));
2170 count += segLen)
2171 {
2172 hibernate_set_page_state(vars->page_list, vars->page_list_wired,
2173 atop_64(phys64), atop_32(segLen),
2174 kIOHibernatePageStateFree);
2175 pageCount -= atop_32(segLen);
2176 }
2177
2178 (void)hibernate_pal_callback;
2179
2180 src = (uint8_t *) vars->srcBuffer->getBytesNoCopy();
2181
2182 pagesDone = 0;
2183 lastBlob = 0;
2184
2185 HIBLOG("writing %d pages\n", pageCount);
2186
2187 enum
2188 // pageType
2189 {
2190 kWired = 0x02,
2191 kEncrypt = 0x01,
2192 kWiredEncrypt = kWired | kEncrypt,
2193 kWiredClear = kWired,
2194 kUnwiredEncrypt = kEncrypt
2195 };
2196
2197 for (pageType = kWiredEncrypt; pageType >= kUnwiredEncrypt; pageType--)
2198 {
2199 if (needEncrypt && (kEncrypt & pageType))
2200 {
2201 vars->fileVars->encryptStart = (vars->fileVars->position & ~(AES_BLOCK_SIZE - 1));
2202 vars->fileVars->encryptEnd = UINT64_MAX;
2203 HIBLOG("encryptStart %qx\n", vars->fileVars->encryptStart);
2204
2205 if (kUnwiredEncrypt == pageType)
2206 {
2207 // start unwired image
2208 bcopy(&cryptvars->aes_iv[0],
2209 &gIOHibernateCryptWakeContext.aes_iv[0],
2210 sizeof(cryptvars->aes_iv));
2211 cryptvars = &gIOHibernateCryptWakeContext;
2212 }
2213 }
2214 for (iterDone = false, ppnum = 0; !iterDone; )
2215 {
2216 count = hibernate_page_list_iterate((kWired & pageType)
2217 ? vars->page_list_wired : vars->page_list,
2218 &ppnum);
2219 // kprintf("[%d](%x : %x)\n", pageType, ppnum, count);
2220 iterDone = !count;
2221
2222 if (count && (kWired & pageType) && needEncrypt)
2223 {
2224 uint32_t checkIndex;
2225 for (checkIndex = 0;
2226 (checkIndex < count)
2227 && (((kEncrypt & pageType) == 0) == no_encrypt_page(ppnum + checkIndex));
2228 checkIndex++)
2229 {}
2230 if (!checkIndex)
2231 {
2232 ppnum++;
2233 continue;
2234 }
2235 count = checkIndex;
2236 }
2237
2238 switch (pageType)
2239 {
2240 case kWiredEncrypt: wired_pages_encrypted += count; break;
2241 case kWiredClear: wired_pages_clear += count; break;
2242 case kUnwiredEncrypt: dirty_pages_encrypted += count; break;
2243 }
2244
2245 if (iterDone && (kWiredEncrypt == pageType)) {/* not yet end of wired list */}
2246 else
2247 {
2248 pageAndCount[0] = ppnum;
2249 pageAndCount[1] = count;
2250 err = IOPolledFileWrite(vars->fileVars,
2251 (const uint8_t *) &pageAndCount, sizeof(pageAndCount),
2252 cryptvars);
2253 if (kIOReturnSuccess != err)
2254 break;
2255 }
2256
2257 for (page = ppnum; page < (ppnum + count); page++)
2258 {
2259 err = IOMemoryDescriptorWriteFromPhysical(vars->srcBuffer, 0, ptoa_64(page), page_size);
2260 if (err)
2261 {
2262 HIBLOG("IOMemoryDescriptorWriteFromPhysical %d [%ld] %x\n", __LINE__, (long)page, err);
2263 break;
2264 }
2265
2266 sum = hibernate_sum_page(src, page);
2267 if (kWired & pageType)
2268 sum1 += sum;
2269 else
2270 sum2 += sum;
2271
2272 clock_get_uptime(&startTime);
2273
2274 pageCompressedSize = WKdm_compress ((WK_word*) src, (WK_word*) (src + page_size), PAGE_SIZE_IN_WORDS);
2275
2276 clock_get_uptime(&endTime);
2277 ADD_ABSOLUTETIME(&compTime, &endTime);
2278 SUB_ABSOLUTETIME(&compTime, &startTime);
2279 compBytes += page_size;
2280
2281 if (kIOHibernateModeEncrypt & gIOHibernateMode)
2282 pageCompressedSize = (pageCompressedSize + AES_BLOCK_SIZE - 1) & ~(AES_BLOCK_SIZE - 1);
2283
2284 if (pageCompressedSize > page_size)
2285 {
2286 // HIBLOG("------------lose: %d\n", pageCompressedSize);
2287 pageCompressedSize = page_size;
2288 }
2289
2290 if (pageCompressedSize != page_size)
2291 data = (src + page_size);
2292 else
2293 data = src;
2294
2295 tag = pageCompressedSize | kIOHibernateTagSignature;
2296 err = IOPolledFileWrite(vars->fileVars, (const uint8_t *) &tag, sizeof(tag), cryptvars);
2297 if (kIOReturnSuccess != err)
2298 break;
2299
2300 err = IOPolledFileWrite(vars->fileVars, data, (pageCompressedSize + 3) & ~3, cryptvars);
2301 if (kIOReturnSuccess != err)
2302 break;
2303
2304 compressedSize += pageCompressedSize;
2305 if (pageCompressedSize)
2306 uncompressedSize += page_size;
2307 pagesDone++;
2308
2309 if (vars->consoleMapping && (0 == (1023 & pagesDone)))
2310 {
2311 blob = ((pagesDone * kIOHibernateProgressCount) / pageCount);
2312 if (blob != lastBlob)
2313 {
2314 ProgressUpdate(gIOHibernateGraphicsInfo, vars->consoleMapping, lastBlob, blob);
2315 lastBlob = blob;
2316 }
2317 }
2318 if (0 == (8191 & pagesDone))
2319 {
2320 clock_get_uptime(&endTime);
2321 SUB_ABSOLUTETIME(&endTime, &allTime);
2322 absolutetime_to_nanoseconds(endTime, &nsec);
2323 progressStamp = nsec / 750000000ULL;
2324 if (progressStamp != lastProgressStamp)
2325 {
2326 lastProgressStamp = progressStamp;
2327 HIBPRINT("pages %d (%d%%)\n", pagesDone, (100 * pagesDone) / pageCount);
2328 }
2329 }
2330 }
2331 if (kIOReturnSuccess != err)
2332 break;
2333 ppnum = page;
2334 }
2335
2336 if (kIOReturnSuccess != err)
2337 break;
2338
2339 if ((kEncrypt & pageType))
2340 {
2341 vars->fileVars->encryptEnd = (vars->fileVars->position + AES_BLOCK_SIZE - 1)
2342 & ~(AES_BLOCK_SIZE - 1);
2343 HIBLOG("encryptEnd %qx\n", vars->fileVars->encryptEnd);
2344 }
2345
2346 if (kWiredEncrypt != pageType)
2347 {
2348 // end of image1/2 - fill to next block
2349 err = IOPolledFileWrite(vars->fileVars, 0, 0, cryptvars);
2350 if (kIOReturnSuccess != err)
2351 break;
2352 }
2353 if (kWiredClear == pageType)
2354 {
2355 // end wired image
2356 header->encryptStart = vars->fileVars->encryptStart;
2357 header->encryptEnd = vars->fileVars->encryptEnd;
2358 image1Size = vars->fileVars->position;
2359 HIBLOG("image1Size %qd, encryptStart1 %qx, End1 %qx\n",
2360 image1Size, header->encryptStart, header->encryptEnd);
2361 }
2362 }
2363 if (kIOReturnSuccess != err)
2364 break;
2365
2366 // Header:
2367
2368 header->imageSize = vars->fileVars->position;
2369 header->image1Size = image1Size;
2370 header->bitmapSize = bitmap_size;
2371 header->pageCount = pageCount;
2372
2373 header->restore1Sum = restore1Sum;
2374 header->image1Sum = sum1;
2375 header->image2Sum = sum2;
2376
2377 count = vars->fileExtents->getLength();
2378 if (count > sizeof(header->fileExtentMap))
2379 {
2380 header->fileExtentMapSize = count;
2381 count = sizeof(header->fileExtentMap);
2382 }
2383 else
2384 header->fileExtentMapSize = sizeof(header->fileExtentMap);
2385 bcopy(&fileExtents[0], &header->fileExtentMap[0], count);
2386
2387 header->deviceBase = vars->fileVars->block0;
2388
2389 IOPolledFileSeek(vars->fileVars, 0);
2390 err = IOPolledFileWrite(vars->fileVars,
2391 (uint8_t *) header, sizeof(IOHibernateImageHeader),
2392 cryptvars);
2393 if (kIOReturnSuccess != err)
2394 break;
2395 err = IOPolledFileWrite(vars->fileVars, 0, 0, cryptvars);
2396 if (kIOReturnSuccess != err)
2397 break;
2398 err = IOHibernatePollerIODone(vars->fileVars, true);
2399 if (kIOReturnSuccess != err)
2400 break;
2401 }
2402 while (false);
2403
2404 clock_get_uptime(&endTime);
2405
2406 IOService::getPMRootDomain()->pmStatsRecordEvent(
2407 kIOPMStatsHibernateImageWrite | kIOPMStatsEventStopFlag, endTime);
2408
2409 SUB_ABSOLUTETIME(&endTime, &allTime);
2410 absolutetime_to_nanoseconds(endTime, &nsec);
2411 HIBLOG("all time: %qd ms, ",
2412 nsec / 1000000ULL);
2413
2414 absolutetime_to_nanoseconds(compTime, &nsec);
2415 HIBLOG("comp bytes: %qd time: %qd ms %qd Mb/s, ",
2416 compBytes,
2417 nsec / 1000000ULL,
2418 nsec ? (((compBytes * 1000000000ULL) / 1024 / 1024) / nsec) : 0);
2419
2420 absolutetime_to_nanoseconds(vars->fileVars->cryptTime, &nsec);
2421 HIBLOG("crypt bytes: %qd time: %qd ms %qd Mb/s, ",
2422 vars->fileVars->cryptBytes,
2423 nsec / 1000000ULL,
2424 nsec ? (((vars->fileVars->cryptBytes * 1000000000ULL) / 1024 / 1024) / nsec) : 0);
2425
2426 HIBLOG("\nimage %qd, uncompressed %qd (%d), compressed %qd (%d%%), sum1 %x, sum2 %x\n",
2427 header->imageSize,
2428 uncompressedSize, atop_32(uncompressedSize), compressedSize,
2429 uncompressedSize ? ((int) ((compressedSize * 100ULL) / uncompressedSize)) : 0,
2430 sum1, sum2);
2431
2432 HIBLOG("wired_pages_encrypted %d, wired_pages_clear %d, dirty_pages_encrypted %d\n",
2433 wired_pages_encrypted, wired_pages_clear, dirty_pages_encrypted);
2434
2435 if (vars->fileVars->io)
2436 (void) IOHibernatePollerIODone(vars->fileVars, false);
2437
2438 if (pollerOpen)
2439 IOHibernatePollerClose(vars->fileVars, kIOPolledBeforeSleepState);
2440
2441 if (vars->consoleMapping)
2442 ProgressUpdate(gIOHibernateGraphicsInfo,
2443 vars->consoleMapping, 0, kIOHibernateProgressCount);
2444
2445 HIBLOG("hibernate_write_image done(%x)\n", err);
2446
2447 // should we come back via regular wake, set the state in memory.
2448 gIOHibernateState = kIOHibernateStateInactive;
2449
2450 KERNEL_DEBUG_CONSTANT(IOKDBG_CODE(DBG_HIBERNATE, 1) | DBG_FUNC_END,
2451 wired_pages_encrypted, wired_pages_clear, dirty_pages_encrypted, 0, 0);
2452
2453 if (kIOReturnSuccess == err)
2454 {
2455 if (kIOHibernateModeSleep & gIOHibernateMode)
2456 {
2457 return (kIOHibernatePostWriteSleep);
2458 }
2459 else if(kIOHibernateModeRestart & gIOHibernateMode)
2460 {
2461 return (kIOHibernatePostWriteRestart);
2462 }
2463 else
2464 {
2465 /* by default, power down */
2466 return (kIOHibernatePostWriteHalt);
2467 }
2468 }
2469 else if (kIOReturnAborted == err)
2470 {
2471 return (kIOHibernatePostWriteWake);
2472 }
2473 else
2474 {
2475 /* on error, sleep */
2476 return (kIOHibernatePostWriteSleep);
2477 }
2478 }
2479
2480 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2481
2482 extern "C" void
2483 hibernate_machine_init(void)
2484 {
2485 IOReturn err;
2486 uint32_t sum;
2487 uint32_t pagesDone;
2488 uint32_t pagesRead = 0;
2489 AbsoluteTime startTime, compTime;
2490 AbsoluteTime allTime, endTime;
2491 uint64_t compBytes;
2492 uint64_t nsec;
2493 uint32_t lastProgressStamp = 0;
2494 uint32_t progressStamp;
2495 uint64_t progressZeroPosition = 0;
2496 uint32_t blob, lastBlob = (uint32_t) -1L;
2497 hibernate_cryptvars_t * cryptvars = 0;
2498
2499 IOHibernateVars * vars = &gIOHibernateVars;
2500
2501 if (!vars->fileVars || !vars->fileVars->pollers || !vars->fileExtents)
2502 return;
2503
2504 sum = gIOHibernateCurrentHeader->actualImage1Sum;
2505 pagesDone = gIOHibernateCurrentHeader->actualUncompressedPages;
2506
2507 HIBLOG("hibernate_machine_init: state %d, image pages %d, sum was %x, image1Size %qx, conflictCount %d, nextFree %x\n",
2508 gIOHibernateState, pagesDone, sum, gIOHibernateCurrentHeader->image1Size,
2509 gIOHibernateCurrentHeader->conflictCount, gIOHibernateCurrentHeader->nextFree);
2510
2511 if (kIOHibernateStateWakingFromHibernate != gIOHibernateState)
2512 {
2513 HIBLOG("regular wake\n");
2514 return;
2515 }
2516
2517 HIBPRINT("diag %x %x %x %x\n",
2518 gIOHibernateCurrentHeader->diag[0], gIOHibernateCurrentHeader->diag[1],
2519 gIOHibernateCurrentHeader->diag[2], gIOHibernateCurrentHeader->diag[3]);
2520
2521 HIBPRINT("video %x %d %d %d status %x\n",
2522 gIOHibernateGraphicsInfo->physicalAddress, gIOHibernateGraphicsInfo->depth,
2523 gIOHibernateGraphicsInfo->width, gIOHibernateGraphicsInfo->height, gIOHibernateGraphicsInfo->gfxStatus);
2524
2525 if ((kIOHibernateModeDiscardCleanActive | kIOHibernateModeDiscardCleanInactive) & gIOHibernateMode)
2526 hibernate_page_list_discard(vars->page_list);
2527
2528 boot_args *args = (boot_args *) PE_state.bootArgs;
2529
2530 cryptvars = (kIOHibernateModeEncrypt & gIOHibernateMode) ? &gIOHibernateCryptWakeContext : 0;
2531
2532 if (gIOHibernateCurrentHeader->handoffPageCount > gIOHibernateHandoffPageCount)
2533 panic("handoff overflow");
2534
2535 IOHibernateHandoff * handoff;
2536 bool done = false;
2537 bool foundCryptData = false;
2538
2539 for (handoff = (IOHibernateHandoff *) vars->handoffBuffer->getBytesNoCopy();
2540 !done;
2541 handoff = (IOHibernateHandoff *) &handoff->data[handoff->bytecount])
2542 {
2543 // HIBPRINT("handoff %p, %x, %x\n", handoff, handoff->type, handoff->bytecount);
2544 uint8_t * data = &handoff->data[0];
2545 switch (handoff->type)
2546 {
2547 case kIOHibernateHandoffTypeEnd:
2548 done = true;
2549 break;
2550
2551 case kIOHibernateHandoffTypeGraphicsInfo:
2552 bcopy(data, gIOHibernateGraphicsInfo, sizeof(*gIOHibernateGraphicsInfo));
2553 break;
2554
2555 case kIOHibernateHandoffTypeCryptVars:
2556 if (cryptvars)
2557 {
2558 hibernate_cryptwakevars_t *
2559 wakevars = (hibernate_cryptwakevars_t *) &handoff->data[0];
2560 bcopy(&wakevars->aes_iv[0], &cryptvars->aes_iv[0], sizeof(cryptvars->aes_iv));
2561 }
2562 foundCryptData = true;
2563 bzero(data, handoff->bytecount);
2564 break;
2565
2566 case kIOHibernateHandoffTypeMemoryMap:
2567 hibernate_newruntime_map(data, handoff->bytecount,
2568 gIOHibernateCurrentHeader->systemTableOffset);
2569 break;
2570
2571 case kIOHibernateHandoffTypeDeviceTree:
2572 {
2573 // DTEntry chosen = NULL;
2574 // HIBPRINT("DTLookupEntry %d\n", DTLookupEntry((const DTEntry) data, "/chosen", &chosen));
2575 }
2576 break;
2577
2578 default:
2579 done = (kIOHibernateHandoffType != (handoff->type & 0xFFFF0000));
2580 break;
2581 }
2582 }
2583 if (cryptvars && !foundCryptData)
2584 panic("hibernate handoff");
2585
2586 if (vars->videoMapping
2587 && gIOHibernateGraphicsInfo->physicalAddress
2588 && (args->Video.v_baseAddr == gIOHibernateGraphicsInfo->physicalAddress))
2589 {
2590 vars->videoMapSize = round_page(gIOHibernateGraphicsInfo->height
2591 * gIOHibernateGraphicsInfo->rowBytes);
2592 IOMapPages(kernel_map,
2593 vars->videoMapping, gIOHibernateGraphicsInfo->physicalAddress,
2594 vars->videoMapSize, kIOMapInhibitCache );
2595 }
2596
2597 uint8_t * src = (uint8_t *) vars->srcBuffer->getBytesNoCopy();
2598 uint32_t decoOffset;
2599
2600 clock_get_uptime(&allTime);
2601 AbsoluteTime_to_scalar(&compTime) = 0;
2602 compBytes = 0;
2603
2604 HIBLOG("IOHibernatePollerOpen(), ml_get_interrupts_enabled %d\n", ml_get_interrupts_enabled());
2605 err = IOHibernatePollerOpen(vars->fileVars, kIOPolledAfterSleepState, 0);
2606 HIBLOG("IOHibernatePollerOpen(%x)\n", err);
2607
2608 if (gIOHibernateCurrentHeader->previewSize)
2609 progressZeroPosition = gIOHibernateCurrentHeader->previewSize
2610 + gIOHibernateCurrentHeader->fileExtentMapSize
2611 - sizeof(gIOHibernateCurrentHeader->fileExtentMap)
2612 + ptoa_64(gIOHibernateCurrentHeader->restore1PageCount);
2613
2614 IOPolledFileSeek(vars->fileVars, gIOHibernateCurrentHeader->image1Size);
2615
2616 if (vars->videoMapSize)
2617 {
2618 lastBlob = ((vars->fileVars->position - progressZeroPosition) * kIOHibernateProgressCount)
2619 / (gIOHibernateCurrentHeader->imageSize - progressZeroPosition);
2620 ProgressUpdate(gIOHibernateGraphicsInfo, (uint8_t *) vars->videoMapping, 0, lastBlob);
2621 }
2622
2623 // kick off the read ahead
2624 vars->fileVars->io = false;
2625 vars->fileVars->bufferHalf = 0;
2626 vars->fileVars->bufferLimit = 0;
2627 vars->fileVars->lastRead = 0;
2628 vars->fileVars->readEnd = gIOHibernateCurrentHeader->imageSize;
2629 vars->fileVars->bufferOffset = vars->fileVars->bufferLimit;
2630 vars->fileVars->cryptBytes = 0;
2631 AbsoluteTime_to_scalar(&vars->fileVars->cryptTime) = 0;
2632
2633 err = IOPolledFileRead(vars->fileVars, 0, 0, cryptvars);
2634 vars->fileVars->bufferOffset = vars->fileVars->bufferLimit;
2635 // --
2636
2637 HIBLOG("hibernate_machine_init reading\n");
2638
2639 uint32_t * header = (uint32_t *) src;
2640 sum = 0;
2641
2642 while (kIOReturnSuccess == err)
2643 {
2644 unsigned int count;
2645 unsigned int page;
2646 uint32_t tag;
2647 vm_offset_t ppnum, compressedSize;
2648
2649 err = IOPolledFileRead(vars->fileVars, src, 8, cryptvars);
2650 if (kIOReturnSuccess != err)
2651 break;
2652
2653 ppnum = header[0];
2654 count = header[1];
2655
2656 // HIBPRINT("(%x, %x)\n", ppnum, count);
2657
2658 if (!count)
2659 break;
2660
2661 for (page = 0; page < count; page++)
2662 {
2663 err = IOPolledFileRead(vars->fileVars, (uint8_t *) &tag, 4, cryptvars);
2664 if (kIOReturnSuccess != err)
2665 break;
2666
2667 compressedSize = kIOHibernateTagLength & tag;
2668 if (kIOHibernateTagSignature != (tag & ~kIOHibernateTagLength))
2669 {
2670 err = kIOReturnIPCError;
2671 break;
2672 }
2673
2674 if (!compressedSize)
2675 {
2676 ppnum++;
2677 pagesDone++;
2678 continue;
2679 }
2680
2681 err = IOPolledFileRead(vars->fileVars, src, (compressedSize + 3) & ~3, cryptvars);
2682 if (kIOReturnSuccess != err)
2683 break;
2684
2685 if (compressedSize < page_size)
2686 {
2687 decoOffset = page_size;
2688
2689 clock_get_uptime(&startTime);
2690 WKdm_decompress((WK_word*) src, (WK_word*) (src + decoOffset), PAGE_SIZE_IN_WORDS);
2691 clock_get_uptime(&endTime);
2692 ADD_ABSOLUTETIME(&compTime, &endTime);
2693 SUB_ABSOLUTETIME(&compTime, &startTime);
2694
2695 compBytes += page_size;
2696 }
2697 else
2698 decoOffset = 0;
2699
2700 sum += hibernate_sum_page((src + decoOffset), ppnum);
2701
2702 err = IOMemoryDescriptorReadToPhysical(vars->srcBuffer, decoOffset, ptoa_64(ppnum), page_size);
2703 if (err)
2704 {
2705 HIBLOG("IOMemoryDescriptorReadToPhysical [%ld] %x\n", (long)ppnum, err);
2706 break;
2707 }
2708
2709 ppnum++;
2710 pagesDone++;
2711 pagesRead++;
2712
2713 if (vars->videoMapSize && (0 == (1023 & pagesDone)))
2714 {
2715 blob = ((vars->fileVars->position - progressZeroPosition) * kIOHibernateProgressCount)
2716 / (gIOHibernateCurrentHeader->imageSize - progressZeroPosition);
2717 if (blob != lastBlob)
2718 {
2719 ProgressUpdate(gIOHibernateGraphicsInfo, (uint8_t *) vars->videoMapping, lastBlob, blob);
2720 lastBlob = blob;
2721 }
2722 }
2723
2724 if (0 == (8191 & pagesDone))
2725 {
2726 clock_get_uptime(&endTime);
2727 SUB_ABSOLUTETIME(&endTime, &allTime);
2728 absolutetime_to_nanoseconds(endTime, &nsec);
2729 progressStamp = nsec / 750000000ULL;
2730 if (progressStamp != lastProgressStamp)
2731 {
2732 lastProgressStamp = progressStamp;
2733 HIBPRINT("pages %d (%d%%)\n", pagesDone,
2734 (100 * pagesDone) / gIOHibernateCurrentHeader->pageCount);
2735 }
2736 }
2737 }
2738 }
2739 if (pagesDone == gIOHibernateCurrentHeader->actualUncompressedPages)
2740 err = kIOReturnLockedRead;
2741
2742 if (kIOReturnSuccess != err)
2743 panic("Hibernate restore error %x", err);
2744
2745 gIOHibernateCurrentHeader->actualImage2Sum = sum;
2746
2747 if (vars->fileVars->io)
2748 (void) IOHibernatePollerIODone(vars->fileVars, false);
2749
2750 err = IOHibernatePollerClose(vars->fileVars, kIOPolledAfterSleepState);
2751
2752 if (vars->videoMapSize)
2753 ProgressUpdate(gIOHibernateGraphicsInfo,
2754 (uint8_t *) vars->videoMapping, 0, kIOHibernateProgressCount);
2755
2756 clock_get_uptime(&endTime);
2757
2758 IOService::getPMRootDomain()->pmStatsRecordEvent(
2759 kIOPMStatsHibernateImageRead | kIOPMStatsEventStartFlag, allTime);
2760 IOService::getPMRootDomain()->pmStatsRecordEvent(
2761 kIOPMStatsHibernateImageRead | kIOPMStatsEventStopFlag, endTime);
2762
2763 SUB_ABSOLUTETIME(&endTime, &allTime);
2764 absolutetime_to_nanoseconds(endTime, &nsec);
2765
2766 HIBLOG("hibernate_machine_init pagesDone %d sum2 %x, time: %qd ms, ",
2767 pagesDone, sum, nsec / 1000000ULL);
2768
2769 absolutetime_to_nanoseconds(compTime, &nsec);
2770 HIBLOG("comp bytes: %qd time: %qd ms %qd Mb/s, ",
2771 compBytes,
2772 nsec / 1000000ULL,
2773 nsec ? (((compBytes * 1000000000ULL) / 1024 / 1024) / nsec) : 0);
2774
2775 absolutetime_to_nanoseconds(vars->fileVars->cryptTime, &nsec);
2776 HIBLOG("crypt bytes: %qd time: %qd ms %qd Mb/s\n",
2777 vars->fileVars->cryptBytes,
2778 nsec / 1000000ULL,
2779 nsec ? (((vars->fileVars->cryptBytes * 1000000000ULL) / 1024 / 1024) / nsec) : 0);
2780
2781 KERNEL_DEBUG_CONSTANT(IOKDBG_CODE(DBG_HIBERNATE, 2) | DBG_FUNC_NONE, pagesRead, pagesDone, 0, 0, 0);
2782 }
2783
2784 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */