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