]> git.saurik.com Git - apple/xnu.git/blame - iokit/Kernel/IOPolledInterface.cpp
xnu-4570.61.1.tar.gz
[apple/xnu.git] / iokit / Kernel / IOPolledInterface.cpp
CommitLineData
d1ecb069
A
1/*
2 * Copyright (c) 2006-2009 Apple 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
3e170ce0
A
29#include <sys/uio.h>
30#include <sys/conf.h>
31
32#include <IOKit/IOLib.h>
33#include <IOKit/IOBSD.h>
d1ecb069 34#include <IOKit/IOService.h>
3e170ce0 35#include <IOKit/IOPlatformExpert.h>
d1ecb069 36#include <IOKit/IOPolledInterface.h>
3e170ce0
A
37#include <IOKit/IOHibernatePrivate.h>
38#include <IOKit/IOBufferMemoryDescriptor.h>
39#include <IOKit/AppleKeyStoreInterface.h>
40#include "IOKitKernelInternal.h"
41
d1ecb069
A
42
43/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
44
45OSDefineMetaClassAndAbstractStructors(IOPolledInterface, OSObject);
46
a39ff7e2 47OSMetaClassDefineReservedUsed(IOPolledInterface, 0);
d1ecb069
A
48OSMetaClassDefineReservedUnused(IOPolledInterface, 1);
49OSMetaClassDefineReservedUnused(IOPolledInterface, 2);
50OSMetaClassDefineReservedUnused(IOPolledInterface, 3);
51OSMetaClassDefineReservedUnused(IOPolledInterface, 4);
52OSMetaClassDefineReservedUnused(IOPolledInterface, 5);
53OSMetaClassDefineReservedUnused(IOPolledInterface, 6);
54OSMetaClassDefineReservedUnused(IOPolledInterface, 7);
55OSMetaClassDefineReservedUnused(IOPolledInterface, 8);
56OSMetaClassDefineReservedUnused(IOPolledInterface, 9);
57OSMetaClassDefineReservedUnused(IOPolledInterface, 10);
58OSMetaClassDefineReservedUnused(IOPolledInterface, 11);
59OSMetaClassDefineReservedUnused(IOPolledInterface, 12);
60OSMetaClassDefineReservedUnused(IOPolledInterface, 13);
61OSMetaClassDefineReservedUnused(IOPolledInterface, 14);
62OSMetaClassDefineReservedUnused(IOPolledInterface, 15);
63
3e170ce0
A
64/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
65
66#ifndef kIOMediaPreferredBlockSizeKey
67#define kIOMediaPreferredBlockSizeKey "Preferred Block Size"
68#endif
69
70enum { kDefaultIOSize = 128*1024 };
71
72/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
73
74class IOPolledFilePollers : public OSObject
75{
76 OSDeclareDefaultStructors(IOPolledFilePollers)
77
78public:
79 IOService * media;
80 OSArray * pollers;
81 IOBufferMemoryDescriptor * ioBuffer;
82 bool abortable;
83 bool io;
84 IOReturn ioStatus;
85 uint32_t openCount;
3e170ce0
A
86
87 static IOPolledFilePollers * copyPollers(IOService * media);
88};
89
90OSDefineMetaClassAndStructors(IOPolledFilePollers, OSObject)
91
92/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
93
94IOPolledFilePollers *
95IOPolledFilePollers::copyPollers(IOService * media)
96{
97 IOPolledFilePollers * vars;
98 IOReturn err;
99 IOService * service;
100 OSObject * obj;
101 IORegistryEntry * next;
102 IORegistryEntry * child;
103
104 if ((obj = media->copyProperty(kIOPolledInterfaceStackKey)))
105 {
106 return (OSDynamicCast(IOPolledFilePollers, obj));
107 }
108
109 do
110 {
111 vars = OSTypeAlloc(IOPolledFilePollers);
112 vars->init();
113
114 vars->pollers = OSArray::withCapacity(4);
115 if (!vars->pollers)
116 {
117 err = kIOReturnNoMemory;
118 break;
119 }
120
121 next = vars->media = media;
122 do
123 {
124 IOPolledInterface * poller;
125 OSObject * obj;
126
127 obj = next->getProperty(kIOPolledInterfaceSupportKey);
128 if (kOSBooleanFalse == obj)
129 {
130 vars->pollers->flushCollection();
131 break;
132 }
133 else if ((poller = OSDynamicCast(IOPolledInterface, obj)))
134 vars->pollers->setObject(poller);
135
136 if ((service = OSDynamicCast(IOService, next))
137 && service->getDeviceMemory()
138 && !vars->pollers->getCount()) break;
139
140 child = next;
141 }
142 while ((next = child->getParentEntry(gIOServicePlane))
143 && child->isParent(next, gIOServicePlane, true));
144
145 if (!vars->pollers->getCount())
146 {
147 err = kIOReturnUnsupported;
148 break;
149 }
150 }
151 while (false);
152
153 media->setProperty(kIOPolledInterfaceStackKey, vars);
154
155 return (vars);
156}
157
158/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
159
160static IOReturn
161IOPolledFilePollersIODone(IOPolledFilePollers * vars, bool abortable);
162
163/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
164
165static IOReturn
166IOPolledFilePollersProbe(IOPolledFilePollers * vars)
167{
168 IOReturn err = kIOReturnError;
169 int32_t idx;
170 IOPolledInterface * poller;
171
172 for (idx = vars->pollers->getCount() - 1; idx >= 0; idx--)
173 {
174 poller = (IOPolledInterface *) vars->pollers->getObject(idx);
175 err = poller->probe(vars->media);
176 if (err)
177 {
178 HIBLOG("IOPolledInterface::probe[%d] 0x%x\n", idx, err);
179 break;
180 }
181 }
182
183 return (err);
184}
185
186/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
187
188IOReturn
189IOPolledFilePollersOpen(IOPolledFileIOVars * filevars, uint32_t state, bool abortable)
190{
191
192 IOPolledFilePollers * vars = filevars->pollers;
193 IOBufferMemoryDescriptor * ioBuffer;
194 IOPolledInterface * poller;
195 IOService * next;
196 IOReturn err = kIOReturnError;
197 int32_t idx;
198
199 vars->abortable = abortable;
200 ioBuffer = 0;
201
202 if (kIOPolledAfterSleepState == state)
203 {
204 vars->ioStatus = 0;
205 vars->io = false;
206 }
207 (void) IOPolledFilePollersIODone(vars, false);
208
209 if ((kIOPolledPreflightState == state) || (kIOPolledPreflightCoreDumpState == state))
210 {
211 ioBuffer = vars->ioBuffer;
212 if (!ioBuffer)
213 {
214 vars->ioBuffer = ioBuffer = IOBufferMemoryDescriptor::withOptions(kIODirectionInOut,
215 2 * kDefaultIOSize, page_size);
216 if (!ioBuffer) return (kIOReturnNoMemory);
217 }
218 }
219
220 for (idx = vars->pollers->getCount() - 1; idx >= 0; idx--)
221 {
222 poller = (IOPolledInterface *) vars->pollers->getObject(idx);
223 err = poller->open(state, ioBuffer);
3e170ce0
A
224 if (kIOReturnSuccess != err)
225 {
226 HIBLOG("IOPolledInterface::open[%d] 0x%x\n", idx, err);
227 break;
228 }
229 }
490019cf 230 if ((kIOReturnSuccess == err) && (kIOPolledPreflightState == state))
3e170ce0
A
231 {
232 next = vars->media;
233 while (next)
234 {
235 next->setProperty(kIOPolledInterfaceActiveKey, kOSBooleanTrue);
236 next = next->getProvider();
237 }
238 }
239
240 return (err);
241}
242
243/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
244
245IOReturn
246IOPolledFilePollersClose(IOPolledFileIOVars * filevars, uint32_t state)
247{
248 IOPolledFilePollers * vars = filevars->pollers;
249 IOPolledInterface * poller;
250 IORegistryEntry * next;
251 IOReturn err;
252 int32_t idx;
253
254 (void) IOPolledFilePollersIODone(vars, false);
255
490019cf 256 if ((kIOPolledPostflightState == state) || (kIOPolledPostflightCoreDumpState == state))
3e170ce0
A
257 {
258 vars->openCount--;
3e170ce0
A
259 }
260
261 for (idx = 0, err = kIOReturnSuccess;
262 (poller = (IOPolledInterface *) vars->pollers->getObject(idx));
263 idx++)
264 {
265 err = poller->close(state);
ecc0ceb4
A
266 if ((kIOReturnSuccess != err) && (kIOPolledBeforeSleepStateAborted == state))
267 {
268 err = poller->close(kIOPolledBeforeSleepState);
269 }
3e170ce0
A
270 if (err) HIBLOG("IOPolledInterface::close[%d] 0x%x\n", idx, err);
271 }
272
273 if (kIOPolledPostflightState == state)
490019cf 274 {
3e170ce0
A
275 next = vars->media;
276 while (next)
277 {
278 next->removeProperty(kIOPolledInterfaceActiveKey);
279 next = next->getParentEntry(gIOServicePlane);
280 }
490019cf 281 }
3e170ce0 282
490019cf
A
283 if ((kIOPolledPostflightState == state) || (kIOPolledPostflightCoreDumpState == state)) do
284 {
285 if (vars->openCount) break;
3e170ce0
A
286 if (vars->ioBuffer)
287 {
288 vars->ioBuffer->release();
289 vars->ioBuffer = 0;
290 }
291 }
490019cf
A
292 while (false);
293
3e170ce0
A
294 return (err);
295}
a39ff7e2
A
296
297/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
298
299IOReturn IOPolledInterface::setEncryptionKey(const uint8_t * key, size_t keySize)
300{
301 return (kIOReturnUnsupported);
302}
303
304/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
305
306IOReturn
307IOPolledFilePollersSetEncryptionKey(IOPolledFileIOVars * filevars,
308 const uint8_t * key, size_t keySize)
309{
310 IOReturn ret = kIOReturnUnsupported;
311 IOReturn err;
312 int32_t idx;
313 IOPolledFilePollers * vars = filevars->pollers;
314 IOPolledInterface * poller;
315
316 for (idx = 0;
317 (poller = (IOPolledInterface *) vars->pollers->getObject(idx));
318 idx++)
319 {
320 poller = (IOPolledInterface *) vars->pollers->getObject(idx);
321 err = poller->setEncryptionKey(key, keySize);
322 if (kIOReturnSuccess == err) ret = err;
323 }
324
325 return (ret);
326}
327
3e170ce0
A
328/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
329
330IOMemoryDescriptor *
331IOPolledFileGetIOBuffer(IOPolledFileIOVars * vars)
332{
333 return (vars->pollers->ioBuffer);
334}
335
336/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
337
338static void
339IOPolledIOComplete(void * target,
340 void * parameter,
341 IOReturn status,
342 UInt64 actualByteCount)
343{
344 IOPolledFilePollers * vars = (IOPolledFilePollers *) parameter;
345
346 vars->ioStatus = status;
347}
348
349/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
350
351static IOReturn
352IOStartPolledIO(IOPolledFilePollers * vars,
353 uint32_t operation, uint32_t bufferOffset,
354 uint64_t deviceOffset, uint64_t length)
355{
356 IOReturn err;
357 IOPolledInterface * poller;
358 IOPolledCompletion completion;
359
360 err = vars->ioStatus;
361 if (kIOReturnSuccess != err) return (err);
362
363 completion.target = 0;
364 completion.action = &IOPolledIOComplete;
365 completion.parameter = vars;
366
367 vars->ioStatus = -1;
368
369 poller = (IOPolledInterface *) vars->pollers->getObject(0);
370 err = poller->startIO(operation, bufferOffset, deviceOffset, length, completion);
5ba3f43e
A
371 if (err) {
372 if (kernel_debugger_entry_count) {
373 HIBLOG("IOPolledInterface::startIO[%d] 0x%x\n", 0, err);
374 } else {
375 HIBLOGFROMPANIC("IOPolledInterface::IOStartPolledIO(0x%p, %d, 0x%x, 0x%llx, %llu) : poller->startIO(%d, 0x%x, 0x%llx, %llu, completion) returned 0x%x",
376 vars, operation, bufferOffset, deviceOffset, length, operation, bufferOffset, deviceOffset, length, err);
377 }
378 }
3e170ce0
A
379 return (err);
380}
381
382/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
383
384static IOReturn
385IOPolledFilePollersIODone(IOPolledFilePollers * vars, bool abortable)
386{
387 IOReturn err = kIOReturnSuccess;
388 int32_t idx = 0;
389 IOPolledInterface * poller;
390 AbsoluteTime deadline;
391
392 if (!vars->io) return (kIOReturnSuccess);
393
394 abortable &= vars->abortable;
395
396 clock_interval_to_deadline(2000, kMillisecondScale, &deadline);
397
398 while (-1 == vars->ioStatus)
399 {
400 for (idx = 0;
401 (poller = (IOPolledInterface *) vars->pollers->getObject(idx));
402 idx++)
403 {
404 IOReturn newErr;
405 newErr = poller->checkForWork();
406 if ((newErr == kIOReturnAborted) && !abortable)
407 newErr = kIOReturnSuccess;
408 if (kIOReturnSuccess == err)
409 err = newErr;
410 }
411 if ((false) && (kIOReturnSuccess == err) && (mach_absolute_time() > AbsoluteTime_to_scalar(&deadline)))
412 {
413 HIBLOG("IOPolledInterface::forced timeout\n");
414 vars->ioStatus = kIOReturnTimeout;
415 }
416 }
417 vars->io = false;
418
419#if HIBERNATION
420 if ((kIOReturnSuccess == err) && abortable && hibernate_should_abort())
421 {
422 err = kIOReturnAborted;
423 HIBLOG("IOPolledInterface::checkForWork sw abort\n");
424 }
425#endif
426
427 if (err)
428 {
429 HIBLOG("IOPolledInterface::checkForWork[%d] 0x%x\n", idx, err);
430 }
431 else
432 {
433 err = vars->ioStatus;
434 if (kIOReturnSuccess != err) HIBLOG("IOPolledInterface::ioStatus 0x%x\n", err);
435 }
436
437 return (err);
438}
439
440/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
441/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
442
443struct _OpenFileContext
444{
445 OSData * extents;
446 uint64_t size;
447};
448
449static void
450file_extent_callback(void * ref, uint64_t start, uint64_t length)
451{
452 _OpenFileContext * ctx = (_OpenFileContext *) ref;
453 IOPolledFileExtent extent;
454
455 extent.start = start;
456 extent.length = length;
457 ctx->extents->appendBytes(&extent, sizeof(extent));
458 ctx->size += length;
459}
460
461/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
462
463static IOService *
464IOCopyMediaForDev(dev_t device)
465{
466 OSDictionary * matching;
467 OSNumber * num;
468 OSIterator * iter;
469 IOService * result = 0;
470
471 matching = IOService::serviceMatching("IOMedia");
472 if (!matching)
473 return (0);
474 do
475 {
476 num = OSNumber::withNumber(major(device), 32);
477 if (!num)
478 break;
479 matching->setObject(kIOBSDMajorKey, num);
480 num->release();
481 num = OSNumber::withNumber(minor(device), 32);
482 if (!num)
483 break;
484 matching->setObject(kIOBSDMinorKey, num);
485 num->release();
486 if (!num)
487 break;
488 iter = IOService::getMatchingServices(matching);
489 if (iter)
490 {
491 result = (IOService *) iter->getNextObject();
492 result->retain();
493 iter->release();
494 }
495 }
496 while (false);
497 matching->release();
498
499 return (result);
500}
501
5ba3f43e
A
502#define APFSMEDIA_GETHIBERKEY "getHiberKey"
503
3e170ce0
A
504static IOReturn
505IOGetVolumeCryptKey(dev_t block_dev, OSString ** pKeyUUID,
a39ff7e2 506 uint8_t * volumeCryptKey, size_t * keySize)
3e170ce0
A
507{
508 IOReturn err;
509 IOService * part;
510 OSString * keyUUID = 0;
511 OSString * keyStoreUUID = 0;
512 uuid_t volumeKeyUUID;
513 aks_volume_key_t vek;
9d749ea3 514 size_t callerKeySize;
3e170ce0
A
515
516 static IOService * sKeyStore;
517
518 part = IOCopyMediaForDev(block_dev);
519 if (!part) return (kIOReturnNotFound);
520
9d749ea3 521 callerKeySize = *keySize;
5ba3f43e 522 // Try APFS first
3e170ce0 523 {
5ba3f43e 524 uuid_t volUuid = {0};
a39ff7e2
A
525 err = part->callPlatformFunction(APFSMEDIA_GETHIBERKEY, false, &volUuid, volumeCryptKey, keySize, keySize);
526 if (kIOReturnBadArgument == err)
527 {
528 // apfs fails on buffer size >32
529 *keySize = 32;
530 err = part->callPlatformFunction(APFSMEDIA_GETHIBERKEY, false, &volUuid, volumeCryptKey, keySize, keySize);
531 }
532 if (err != kIOReturnSuccess) *keySize = 0;
533 else
5c9f4661 534 {
5ba3f43e 535 // No need to create uuid string if it's not requested
5c9f4661
A
536 if (pKeyUUID)
537 {
5ba3f43e
A
538 uuid_string_t volUuidStr;
539 uuid_unparse(volUuid, volUuidStr);
540 *pKeyUUID = OSString::withCString(volUuidStr);
541 }
3e170ce0 542
5ba3f43e
A
543 part->release();
544 return kIOReturnSuccess;
545 }
546 }
3e170ce0 547
5ba3f43e
A
548 // Then old CS path
549 err = part->callPlatformFunction(PLATFORM_FUNCTION_GET_MEDIA_ENCRYPTION_KEY_UUID, false,
550 (void *) &keyUUID, (void *) &keyStoreUUID, NULL, NULL);
551 if ((kIOReturnSuccess == err) && keyUUID && keyStoreUUID)
552 {
553// IOLog("got volume key %s\n", keyStoreUUID->getCStringNoCopy());
554
555 if (!sKeyStore)
556 sKeyStore = (IOService *) IORegistryEntry::fromPath(AKS_SERVICE_PATH, gIOServicePlane);
557 if (sKeyStore)
558 err = uuid_parse(keyStoreUUID->getCStringNoCopy(), volumeKeyUUID);
559 else
560 err = kIOReturnNoResources;
561 if (kIOReturnSuccess == err)
562 err = sKeyStore->callPlatformFunction(gAKSGetKey, true, volumeKeyUUID, &vek, NULL, NULL);
563 if (kIOReturnSuccess != err)
564 IOLog("volume key err 0x%x\n", err);
565 else
566 {
9d749ea3 567 if (vek.key.keybytecount <= callerKeySize) *keySize = vek.key.keybytecount;
a39ff7e2 568 bcopy(&vek.key.keybytes[0], volumeCryptKey, *keySize);
5ba3f43e
A
569 }
570 bzero(&vek, sizeof(vek));
5c9f4661
A
571
572 if (pKeyUUID)
573 {
574 // Create a copy because the caller would release it
575 *pKeyUUID = OSString::withString(keyUUID);
576 }
3e170ce0 577 }
5ba3f43e 578
3e170ce0 579 part->release();
3e170ce0
A
580 return (err);
581}
582
583/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
584
d1ecb069 585IOReturn
3e170ce0 586IOPolledFileOpen(const char * filename,
5c9f4661
A
587 uint64_t setFileSize, uint64_t fsFreeSize,
588 void * write_file_addr, size_t write_file_len,
589 IOPolledFileIOVars ** fileVars,
590 OSData ** imagePath,
a39ff7e2 591 uint8_t * volumeCryptKey, size_t * keySize)
d1ecb069 592{
3e170ce0
A
593 IOReturn err = kIOReturnSuccess;
594 IOPolledFileIOVars * vars;
595 _OpenFileContext ctx;
5ba3f43e 596 OSData * extentsData = NULL;
3e170ce0
A
597 OSNumber * num;
598 IOService * part = 0;
599 dev_t block_dev;
600 dev_t image_dev;
601 AbsoluteTime startTime, endTime;
602 uint64_t nsec;
603
604 vars = IONew(IOPolledFileIOVars, 1);
605 if (!vars) return (kIOReturnNoMemory);
606 bzero(vars, sizeof(*vars));
607 vars->allocated = true;
608
609 do
610 {
5c9f4661
A
611 extentsData = OSData::withCapacity(32);
612 ctx.extents = extentsData;
613 ctx.size = 0;
614 clock_get_uptime(&startTime);
3e170ce0 615
5c9f4661 616 vars->fileRef = kern_open_file_for_direct_io(filename,
3e170ce0 617 (write_file_addr != NULL) || (0 != setFileSize),
5c9f4661
A
618 &file_extent_callback, &ctx,
619 setFileSize,
620 fsFreeSize,
621 // write file:
3e170ce0
A
622 0, write_file_addr, write_file_len,
623 // results
5c9f4661
A
624 &block_dev,
625 &image_dev,
3e170ce0
A
626 &vars->block0,
627 &vars->maxiobytes,
628 &vars->flags);
629#if 0
5c9f4661
A
630 uint32_t msDelay = (131071 & random());
631 HIBLOG("sleep %d\n", msDelay);
632 IOSleep(msDelay);
3e170ce0
A
633#endif
634 clock_get_uptime(&endTime);
635 SUB_ABSOLUTETIME(&endTime, &startTime);
636 absolutetime_to_nanoseconds(endTime, &nsec);
637
5c9f4661 638 if (!vars->fileRef) err = kIOReturnNoSpace;
3e170ce0
A
639
640 HIBLOG("kern_open_file_for_direct_io took %qd ms\n", nsec / 1000000ULL);
5c9f4661 641 if (kIOReturnSuccess != err) break;
3e170ce0 642
5c9f4661
A
643 HIBLOG("Opened file %s, size %qd, extents %ld, maxio %qx ssd %d\n", filename, ctx.size,
644 (extentsData->getLength() / sizeof(IOPolledFileExtent)) - 1,
645 vars->maxiobytes, kIOPolledFileSSD & vars->flags);
646 assert(!vars->block0);
647 if (extentsData->getLength() < sizeof(IOPolledFileExtent))
648 {
649 err = kIOReturnNoSpace;
650 break;
651 }
3e170ce0 652
5c9f4661
A
653 vars->fileSize = ctx.size;
654 vars->extentMap = (IOPolledFileExtent *) extentsData->getBytesNoCopy();
3e170ce0
A
655
656 part = IOCopyMediaForDev(image_dev);
657 if (!part)
658 {
659 err = kIOReturnNotFound;
660 break;
5c9f4661 661 }
3e170ce0 662
5c9f4661 663 if (!(vars->pollers = IOPolledFilePollers::copyPollers(part))) break;
3e170ce0 664
5c9f4661
A
665 if ((num = OSDynamicCast(OSNumber, part->getProperty(kIOMediaPreferredBlockSizeKey))))
666 vars->blockSize = num->unsigned32BitValue();
667 if (vars->blockSize < 4096) vars->blockSize = 4096;
3e170ce0
A
668
669 HIBLOG("polled file major %d, minor %d, blocksize %ld, pollers %d\n",
5c9f4661 670 major(image_dev), minor(image_dev), (long)vars->blockSize,
3e170ce0
A
671 vars->pollers->pollers->getCount());
672
673 OSString * keyUUID = NULL;
674 if (volumeCryptKey)
675 {
676 err = IOGetVolumeCryptKey(block_dev, &keyUUID, volumeCryptKey, keySize);
677 }
678
5c9f4661
A
679 *fileVars = vars;
680 vars->fileExtents = extentsData;
681
682 // make imagePath
683 OSData * data;
684 if (imagePath)
685 {
3e170ce0 686#if defined(__i386__) || defined(__x86_64__)
5c9f4661 687 char str2[24 + sizeof(uuid_string_t) + 2];
3e170ce0
A
688
689 if (keyUUID)
5c9f4661
A
690 snprintf(str2, sizeof(str2), "%qx:%s",
691 vars->extentMap[0].start, keyUUID->getCStringNoCopy());
3e170ce0
A
692 else
693 snprintf(str2, sizeof(str2), "%qx", vars->extentMap[0].start);
694
5c9f4661
A
695 err = IOService::getPlatform()->callPlatformFunction(
696 gIOCreateEFIDevicePathSymbol, false,
697 (void *) part, (void *) str2,
698 (void *) (uintptr_t) true, (void *) &data);
3e170ce0 699#else
5c9f4661
A
700 data = 0;
701 err = kIOReturnSuccess;
3e170ce0 702#endif
5c9f4661
A
703 if (kIOReturnSuccess != err)
704 {
705 HIBLOG("error 0x%x getting path\n", err);
706 break;
707 }
708 *imagePath = data;
709 }
710
711 // Release key UUID if we have one
712 if (keyUUID)
713 {
714 keyUUID->release();
715 keyUUID = NULL; // Just in case
716 }
3e170ce0
A
717 }
718 while (false);
719
720 if (kIOReturnSuccess != err)
721 {
722 HIBLOG("error 0x%x opening polled file\n", err);
5c9f4661
A
723 IOPolledFileClose(&vars, 0, 0, 0, 0, 0);
724 if (extentsData) extentsData->release();
3e170ce0
A
725 }
726
727 if (part) part->release();
d1ecb069 728
3e170ce0 729 return (err);
d1ecb069 730}
3e170ce0
A
731
732/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
733
734IOReturn
735IOPolledFileClose(IOPolledFileIOVars ** pVars,
736 off_t write_offset, void * addr, size_t write_length,
737 off_t discard_offset, off_t discard_end)
738{
739 IOPolledFileIOVars * vars;
740
741 vars = *pVars;
742 if (!vars) return(kIOReturnSuccess);
743
744 if (vars->fileRef)
745 {
746 kern_close_file_for_direct_io(vars->fileRef, write_offset, addr, write_length,
747 discard_offset, discard_end);
748 vars->fileRef = NULL;
749 }
750 if (vars->fileExtents)
751 {
752 vars->fileExtents->release();
753 vars->fileExtents = 0;
754 }
755 if (vars->pollers)
756 {
757 vars->pollers->release();
758 vars->pollers = 0;
759 }
760
761 if (vars->allocated) IODelete(vars, IOPolledFileIOVars, 1);
762 else bzero(vars, sizeof(IOPolledFileIOVars));
763 *pVars = NULL;
764
765 return (kIOReturnSuccess);
766}
767
768/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
769
770IOReturn
771IOPolledFilePollersSetup(IOPolledFileIOVars * vars,
772 uint32_t openState)
773{
774 IOReturn err;
775
776 err = kIOReturnSuccess;
777 do
778 {
779 if (!vars->pollers->openCount)
780 {
781 err = IOPolledFilePollersProbe(vars->pollers);
782 if (kIOReturnSuccess != err) break;
3e170ce0 783 }
490019cf
A
784 err = IOPolledFilePollersOpen(vars, openState, false);
785 if (kIOReturnSuccess != err) break;
786 if ((kIOPolledPreflightState == openState) || (kIOPolledPreflightCoreDumpState == openState))
787 {
788 vars->pollers->openCount++;
789 }
3e170ce0
A
790 vars->pollers->io = false;
791 vars->buffer = (uint8_t *) vars->pollers->ioBuffer->getBytesNoCopy();
792 vars->bufferHalf = 0;
793 vars->bufferOffset = 0;
794 vars->bufferSize = (vars->pollers->ioBuffer->getLength() >> 1);
795
796 if (vars->maxiobytes < vars->bufferSize) vars->bufferSize = vars->maxiobytes;
797 }
798 while (false);
799
800 if (kIOReturnSuccess != err) HIBLOG("IOPolledFilePollersSetup(%d) error 0x%x\n", openState, err);
801
802 return (err);
803}
804
805
806/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
807
808IOReturn
809IOPolledFileSeek(IOPolledFileIOVars * vars, uint64_t position)
810{
811 IOPolledFileExtent * extentMap;
812
813 extentMap = vars->extentMap;
814
815 vars->position = position;
816
5ba3f43e
A
817 if (position > vars->fileSize) {
818 HIBLOG("IOPolledFileSeek: called to seek to 0x%llx greater than file size of 0x%llx\n", vars->position, vars->fileSize);
819 return kIOReturnNoSpace;
820 }
821
3e170ce0
A
822 while (position >= extentMap->length)
823 {
824 position -= extentMap->length;
825 extentMap++;
826 }
827
828 vars->currentExtent = extentMap;
829 vars->extentRemaining = extentMap->length - position;
830 vars->extentPosition = vars->position - position;
831
832 if (vars->bufferSize <= vars->extentRemaining)
833 vars->bufferLimit = vars->bufferSize;
834 else
835 vars->bufferLimit = vars->extentRemaining;
836
837 return (kIOReturnSuccess);
838}
839
840/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
841
842IOReturn
843IOPolledFileWrite(IOPolledFileIOVars * vars,
844 const uint8_t * bytes, IOByteCount size,
845 IOPolledFileCryptVars * cryptvars)
846{
847 IOReturn err = kIOReturnSuccess;
5ba3f43e 848 IOByteCount copy, original_size = size;
3e170ce0
A
849 bool flush = false;
850
851 do
852 {
853 if (!bytes && !size)
854 {
855 // seek to end of block & flush
856 size = vars->position & (vars->blockSize - 1);
857 if (size)
858 size = vars->blockSize - size;
859 flush = true;
860 // use some garbage for the fill
861 bytes = vars->buffer + vars->bufferOffset;
862 }
863
864 copy = vars->bufferLimit - vars->bufferOffset;
865 if (copy > size)
866 copy = size;
867 else
868 flush = true;
869
870 if (bytes)
871 {
5c9f4661
A
872#if KASAN
873 /* Since this may copy mach-o segments in bulk, use the nosan variants of bcopy to
874 * avoid triggering global redzone sanitizer violations when accessing
875 * interstices between 'C' structures
876 */
877 __nosan_bcopy(bytes, vars->buffer + vars->bufferHalf + vars->bufferOffset, copy);
878#else
3e170ce0 879 bcopy(bytes, vars->buffer + vars->bufferHalf + vars->bufferOffset, copy);
5c9f4661 880#endif
3e170ce0
A
881 bytes += copy;
882 }
883 else
884 bzero(vars->buffer + vars->bufferHalf + vars->bufferOffset, copy);
885
886 size -= copy;
887 vars->bufferOffset += copy;
888 vars->position += copy;
889
890 if (flush && vars->bufferOffset)
891 {
892 uint64_t offset = (vars->position - vars->bufferOffset
893 - vars->extentPosition + vars->currentExtent->start);
894 uint32_t length = (vars->bufferOffset);
895
896#if CRYPTO
897 if (cryptvars && vars->encryptStart
898 && (vars->position > vars->encryptStart)
899 && ((vars->position - length) < vars->encryptEnd))
900 {
901 AbsoluteTime startTime, endTime;
902
903 uint64_t encryptLen, encryptStart;
904 encryptLen = vars->position - vars->encryptStart;
905 if (encryptLen > length)
906 encryptLen = length;
907 encryptStart = length - encryptLen;
908 if (vars->position > vars->encryptEnd)
909 encryptLen -= (vars->position - vars->encryptEnd);
910
911 clock_get_uptime(&startTime);
912
913 // encrypt the buffer
914 aes_encrypt_cbc(vars->buffer + vars->bufferHalf + encryptStart,
915 &cryptvars->aes_iv[0],
916 encryptLen / AES_BLOCK_SIZE,
917 vars->buffer + vars->bufferHalf + encryptStart,
918 &cryptvars->ctx.encrypt);
919
920 clock_get_uptime(&endTime);
921 ADD_ABSOLUTETIME(&vars->cryptTime, &endTime);
922 SUB_ABSOLUTETIME(&vars->cryptTime, &startTime);
923 vars->cryptBytes += encryptLen;
924
925 // save initial vector for following encrypts
926 bcopy(vars->buffer + vars->bufferHalf + encryptStart + encryptLen - AES_BLOCK_SIZE,
927 &cryptvars->aes_iv[0],
928 AES_BLOCK_SIZE);
929 }
930#endif /* CRYPTO */
931
932 err = IOPolledFilePollersIODone(vars->pollers, true);
933 if (kIOReturnSuccess != err)
934 break;
935
936if (vars->position & (vars->blockSize - 1)) HIBLOG("misaligned file pos %qx\n", vars->position);
937//if (length != vars->bufferSize) HIBLOG("short write of %qx ends@ %qx\n", length, offset + length);
938
939 err = IOStartPolledIO(vars->pollers, kIOPolledWrite, vars->bufferHalf, offset, length);
5ba3f43e
A
940 if (kIOReturnSuccess != err) {
941 HIBLOGFROMPANIC("IOPolledFileWrite(0x%p, 0x%p, %llu, 0x%p) : IOStartPolledIO(0x%p, kIOPolledWrite, %llu, 0x%llx, %d) returned 0x%x\n",
942 vars, bytes, (uint64_t) original_size, cryptvars, vars->pollers, (uint64_t) vars->bufferHalf, offset, length, err);
3e170ce0 943 break;
5ba3f43e 944 }
3e170ce0
A
945 vars->pollers->io = true;
946
947 vars->extentRemaining -= vars->bufferOffset;
948 if (!vars->extentRemaining)
949 {
950 vars->currentExtent++;
951 vars->extentRemaining = vars->currentExtent->length;
952 vars->extentPosition = vars->position;
953 }
954
955 vars->bufferHalf = vars->bufferHalf ? 0 : vars->bufferSize;
956 vars->bufferOffset = 0;
957 if (vars->bufferSize <= vars->extentRemaining)
958 vars->bufferLimit = vars->bufferSize;
959 else
960 vars->bufferLimit = vars->extentRemaining;
961
962 if (!vars->extentRemaining)
963 {
964 err = kIOReturnOverrun;
965 break;
966 }
967
968 flush = false;
969 }
970 }
971 while (size);
972
973 return (err);
974}
975
976/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
977
5ba3f43e
A
978IOReturn
979IOPolledFileFlush(IOPolledFileIOVars * vars)
980{
981 // Only supported by the underlying polled mode driver on embedded currently (expect kIOReturnUnsupported on other platforms)
982 IOReturn err = kIOReturnSuccess;
983
984 err = IOPolledFilePollersIODone(vars->pollers, true);
985 if (kIOReturnSuccess != err)
986 return err;
987
988 err = IOStartPolledIO(vars->pollers, kIOPolledFlush, 0, 0, 0);
989 if (kIOReturnSuccess != err) {
990 HIBLOGFROMPANIC("IOPolledFileFlush(0x%p) : IOStartPolledIO(0x%p, kIOPolledFlush, 0, 0, 0) returned 0x%x\n",
991 vars, vars->pollers, err);
992 return err;
993 }
994 vars->pollers->io = true;
995
996 return err;
997}
998
999/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1000
3e170ce0
A
1001IOReturn
1002IOPolledFileRead(IOPolledFileIOVars * vars,
1003 uint8_t * bytes, IOByteCount size,
1004 IOPolledFileCryptVars * 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 {
5c9f4661
A
1019#if KASAN
1020 __nosan_bcopy(vars->buffer + vars->bufferHalf + vars->bufferOffset, bytes, copy);
1021#else
1022 bcopy(vars->buffer + vars->bufferHalf + vars->bufferOffset, bytes, copy);
1023#endif
3e170ce0
A
1024 bytes += copy;
1025 }
1026 size -= copy;
1027 vars->bufferOffset += copy;
1028// vars->position += copy;
1029
1030 if ((vars->bufferOffset == vars->bufferLimit) && (vars->position < vars->readEnd))
1031 {
1032 if (!vars->pollers->io) cryptvars = 0;
1033 err = IOPolledFilePollersIODone(vars->pollers, true);
1034 if (kIOReturnSuccess != err)
1035 break;
1036
1037if (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 = IOStartPolledIO(vars->pollers, kIOPolledRead, vars->bufferHalf, offset, length);
1071 if (kIOReturnSuccess != err)
1072 break;
1073 vars->pollers->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