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