]>
Commit | Line | Data |
---|---|---|
2d21ac55 | 1 | /* |
39037602 | 2 | * Copyright (c) 2002-2016 Apple Inc. All rights reserved. |
2d21ac55 A |
3 | * |
4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ | |
0a7de745 | 5 | * |
2d21ac55 A |
6 | * This file contains Original Code and/or Modifications of Original Code |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. The rights granted to you under the License | |
10 | * may not be used to create, or enable the creation or redistribution of, | |
11 | * unlawful or unlicensed copies of an Apple operating system, or to | |
12 | * circumvent, violate, or enable the circumvention or violation of, any | |
13 | * terms of an Apple operating system software license agreement. | |
0a7de745 | 14 | * |
2d21ac55 A |
15 | * Please obtain a copy of the License at |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
0a7de745 | 17 | * |
2d21ac55 A |
18 | * The Original Code and all software distributed under the License are |
19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
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. | |
0a7de745 | 25 | * |
2d21ac55 A |
26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ |
27 | */ | |
9bccf70c A |
28 | /* |
29 | * DINetBootHook.c | |
30 | * DiskImages | |
31 | * | |
32 | * Created by Byron Han on Sat Apr 13 2002. | |
9bccf70c A |
33 | * |
34 | * Revision History | |
35 | * | |
36 | * $Log: DINetBootHook.cpp,v $ | |
2d21ac55 A |
37 | * Revision 1.4 2005/07/29 21:49:57 lindak |
38 | * Merge of branch "chardonnay" to pick up all chardonnay changes in Leopard | |
39 | * as of xnu-792.7.4 | |
40 | * | |
0c530ab8 A |
41 | * Revision 1.3.1558.1 2005/06/24 01:47:25 lindak |
42 | * Bringing over all of the Karma changes into chardonnay. | |
0a7de745 | 43 | * |
0c530ab8 A |
44 | * Revision 1.1.1.1 2005/02/24 21:48:06 akosut |
45 | * Import xnu-764 from Tiger8A395 | |
0a7de745 | 46 | * |
9bccf70c A |
47 | * Revision 1.3 2002/06/16 20:36:02 lindak |
48 | * Merged PR-2957314 into Jaguar (siegmund: netboot kernel code needs to set | |
49 | * com.apple.AppleDiskImageController.load to boolean Yes) | |
0a7de745 | 50 | * |
9bccf70c A |
51 | * Revision 1.2.40.2 2002/06/15 03:50:38 dieter |
52 | * - corrected com.apple.AppleDiskImageController.load string | |
0a7de745 | 53 | * |
9bccf70c A |
54 | * Revision 1.2.40.1 2002/06/15 03:01:08 dieter |
55 | * Bug #: 2957314 | |
56 | * - add call to force IOHDIXController to get loaded/matched | |
0a7de745 | 57 | * |
9bccf70c A |
58 | * Revision 1.2 2002/05/03 18:08:39 lindak |
59 | * Merged PR-2909558 into Jaguar (siegmund POST WWDC: add support for NetBoot | |
60 | * over IOHDIXController) | |
0a7de745 | 61 | * |
9bccf70c A |
62 | * Revision 1.1.2.1 2002/04/24 22:29:12 dieter |
63 | * Bug #: 2909558 | |
64 | * - added IOHDIXController netboot stubs | |
0a7de745 | 65 | * |
9bccf70c A |
66 | * Revision 1.3 2002/04/16 00:41:37 han |
67 | * migrated code out of here to IOHDIXController's setProperty method | |
0a7de745 | 68 | * |
9bccf70c A |
69 | * Revision 1.2 2002/04/14 23:53:53 han |
70 | * eliminate qDEBUG=1, use emums instead of hard coded string constants | |
0a7de745 | 71 | * |
9bccf70c A |
72 | * Revision 1.1 2002/04/14 22:54:42 han |
73 | * Renamed from DINetBookHook.c. | |
74 | * First stab at implementing this code. | |
0a7de745 | 75 | * |
9bccf70c A |
76 | * Revision 1.1 2002/04/13 19:22:28 han |
77 | * added stub file DINetBookHook.c | |
0a7de745 | 78 | * |
9bccf70c A |
79 | * |
80 | */ | |
81 | #ifndef qDEBUG | |
82 | #define qDEBUG 0 | |
83 | #endif | |
84 | ||
85 | #if qDEBUG | |
86 | #warning qDEBUG is 1! | |
87 | #endif | |
88 | ||
89 | #include <sys/types.h> | |
f427ee49 | 90 | #include <mach/clock_types.h> |
9bccf70c A |
91 | #include <IOKit/IOService.h> |
92 | #include <IOKit/IOLib.h> | |
39037602 | 93 | #include "DINetBootHook.h" |
9bccf70c | 94 | |
0a7de745 A |
95 | #define kIOHDIXControllerClassName "IOHDIXController" |
96 | #define kDIRootImageKey "di-root-image" | |
f427ee49 | 97 | #define kDIRootImageRemovableKey "di-root-removable" |
0a7de745 A |
98 | #define kDIRootImageResultKey "di-root-image-result" |
99 | #define kDIRootImageDevNameKey "di-root-image-devname" | |
100 | #define kDIRootImageDevTKey "di-root-image-devt" | |
6d2010ae A |
101 | #define kDIRootRamFileKey "di-root-ram-file" |
102 | ||
f427ee49 A |
103 | #define kDIMatchQuiesceTimeout 30ull |
104 | ||
6d2010ae A |
105 | static IOService * |
106 | di_load_controller( void ) | |
107 | { | |
cb323159 A |
108 | OSIterator * controllerIterator = NULL; |
109 | OSDictionary * matchDictionary = NULL; | |
110 | IOService * controller = NULL; | |
0a7de745 A |
111 | |
112 | do { | |
113 | IOService::getResourceService()->publishResource("com.apple.AppleDiskImageController.load", kOSBooleanTrue); | |
114 | IOService::getResourceService()->waitQuiet(); | |
115 | ||
116 | // first find IOHDIXController | |
117 | matchDictionary = IOService::serviceMatching(kIOHDIXControllerClassName); | |
118 | if (!matchDictionary) { | |
119 | break; | |
120 | } | |
121 | ||
122 | controllerIterator = IOService::getMatchingServices(matchDictionary); | |
123 | if (!controllerIterator) { | |
124 | break; | |
125 | } | |
126 | ||
127 | controller = OSDynamicCast(IOService, controllerIterator->getNextObject()); | |
128 | if (!controller) { | |
129 | break; | |
130 | } | |
131 | ||
132 | controller->retain(); | |
133 | } while (false); | |
134 | ||
135 | if (matchDictionary) { | |
136 | matchDictionary->release(); | |
137 | } | |
138 | if (controllerIterator) { | |
139 | controllerIterator->release(); | |
140 | } | |
6d2010ae | 141 | |
0a7de745 | 142 | return controller; |
6d2010ae | 143 | } |
9bccf70c A |
144 | |
145 | extern "C" { | |
f427ee49 A |
146 | /* FIXME: removable should be replaced with a struct (so it could be easily |
147 | * extensible in the future). However, since there is no common header file | |
148 | * between imageboot and NetBoot, we opt for a simple bool for now. | |
149 | * Refactor this into a common header file. | |
0a7de745 | 150 | */ |
f427ee49 A |
151 | static int |
152 | di_add_properties(IOService *controller, bool removable) | |
153 | { | |
154 | if (!controller->setProperty(kDIRootImageRemovableKey, removable ? kOSBooleanTrue : kOSBooleanFalse)) { | |
155 | IOLog("IOHDIXController::setProperty(%s, %d) failed.\n", kDIRootImageRemovableKey, !!removable); | |
156 | return kIOReturnBadArgument; | |
157 | } | |
158 | ||
159 | return kIOReturnSuccess; | |
160 | } | |
161 | ||
0a7de745 | 162 | int |
f427ee49 | 163 | di_root_image_ext(const char *path, char *devname, size_t devsz, dev_t *dev_p, bool removable) |
9bccf70c | 164 | { |
0a7de745 | 165 | IOReturn res = 0; |
cb323159 A |
166 | IOService * controller = NULL; |
167 | OSString * pathString = NULL; | |
168 | OSNumber * myResult = NULL; | |
169 | OSString * myDevName = NULL; | |
170 | OSNumber * myDevT = NULL; | |
0a7de745 | 171 | |
9bccf70c | 172 | // sanity check arguments please |
0a7de745 A |
173 | if (devname) { |
174 | *devname = 0; | |
175 | } | |
176 | if (dev_p) { | |
177 | *dev_p = 0; | |
178 | } | |
179 | ||
180 | if (!path) { | |
181 | return kIOReturnBadArgument; | |
182 | } | |
183 | if (!devname) { | |
184 | return kIOReturnBadArgument; | |
185 | } | |
186 | if (!dev_p) { | |
187 | return kIOReturnBadArgument; | |
188 | } | |
189 | ||
190 | controller = di_load_controller(); | |
9bccf70c A |
191 | if (!controller) { |
192 | res = kIOReturnNotFound; | |
193 | goto NoIOHDIXController; | |
194 | } | |
0a7de745 | 195 | |
9bccf70c A |
196 | // okay create path object |
197 | pathString = OSString::withCString(path); | |
198 | if (!pathString) { | |
199 | res = kIOReturnNoMemory; | |
200 | goto CannotCreatePathOSString; | |
201 | } | |
0a7de745 | 202 | |
f427ee49 A |
203 | /* |
204 | * This is a bit racy, as two concurrent attached could have | |
205 | * different properties. However, since we query the result and dev | |
206 | * below locklessly, the existing code is already racy, so we | |
207 | * keep the status quo. | |
208 | */ | |
209 | res = di_add_properties(controller, removable); | |
210 | if (res) { | |
211 | goto error_add_properties; | |
212 | } | |
213 | ||
9bccf70c | 214 | // do it |
0a7de745 | 215 | if (!controller->setProperty(kDIRootImageKey, pathString)) { |
9bccf70c | 216 | IOLog("IOHDIXController::setProperty(%s, %s) failed.\n", kDIRootImageKey, pathString->getCStringNoCopy()); |
0a7de745 A |
217 | } |
218 | ||
9bccf70c A |
219 | myResult = OSDynamicCast(OSNumber, controller->getProperty(kDIRootImageResultKey)); |
220 | res = kIOReturnError; | |
0a7de745 | 221 | if (myResult) { |
9bccf70c | 222 | res = myResult->unsigned32BitValue(); |
0a7de745 A |
223 | } |
224 | ||
9bccf70c A |
225 | if (res) { |
226 | IOLog("%s is 0x%08X/%d\n", kDIRootImageResultKey, res, res); | |
227 | goto di_root_image_FAILED; | |
228 | } | |
229 | ||
0a7de745 | 230 | // success - grab |
9bccf70c | 231 | myDevT = OSDynamicCast(OSNumber, controller->getProperty(kDIRootImageDevTKey)); |
0a7de745 | 232 | if (myDevT) { |
9bccf70c | 233 | *dev_p = myDevT->unsigned32BitValue(); |
0a7de745 | 234 | } else { |
9bccf70c A |
235 | IOLog("could not get %s\n", kDIRootImageDevTKey); |
236 | res = kIOReturnError; | |
237 | goto di_root_image_FAILED; | |
238 | } | |
0a7de745 | 239 | |
9bccf70c | 240 | myDevName = OSDynamicCast(OSString, controller->getProperty(kDIRootImageDevNameKey)); |
2d21ac55 | 241 | if (myDevName) { |
5ba3f43e | 242 | strlcpy(devname, myDevName->getCStringNoCopy(), devsz); |
2d21ac55 | 243 | } else { |
9bccf70c A |
244 | IOLog("could not get %s\n", kDIRootImageDevNameKey); |
245 | res = kIOReturnError; | |
246 | goto di_root_image_FAILED; | |
247 | } | |
0a7de745 | 248 | |
f427ee49 A |
249 | /* |
250 | * NOTE: The attached disk image may trigger IOKit matching. At the very least, an IOMedia | |
251 | * must claim it. More complex scenarios might include a GPT containing a partition mapping | |
252 | * to an APFS container, both of which need to probe and claim their respective media devices. | |
253 | * | |
254 | * After the attach is complete, we should quiesce the disk image controller before returning | |
255 | * from this function successfully. If we failed to quiesce, then we should treat it as a hard | |
256 | * failure, to make it more obvious to triage. | |
257 | */ | |
258 | res = controller->waitQuiet((NSEC_PER_SEC * kDIMatchQuiesceTimeout)); | |
259 | if (res) { | |
260 | IOLog("failed to quiesce attached disk image (%s)! \n", devname); | |
261 | goto di_root_image_FAILED; | |
262 | } | |
9bccf70c A |
263 | |
264 | di_root_image_FAILED: | |
265 | CannotCreatePathOSString: | |
9bccf70c | 266 | NoIOHDIXController: |
f427ee49 | 267 | error_add_properties: |
9bccf70c A |
268 | |
269 | // clean up memory allocations | |
0a7de745 A |
270 | if (pathString) { |
271 | pathString->release(); | |
272 | } | |
273 | if (controller) { | |
274 | controller->release(); | |
275 | } | |
9bccf70c A |
276 | |
277 | return res; | |
278 | } | |
279 | ||
f427ee49 A |
280 | /* |
281 | * Name: di_root_image | |
282 | * Function: mount the disk image returning the dev node | |
283 | * Parameters: path -> path/url to disk image | |
284 | * devname <- dev node used to set the rootdevice global variable | |
285 | * dev_p <- device number generated from major/minor numbers | |
286 | * Comments: | |
287 | * This is an exported function. Changing this will break API. | |
288 | */ | |
289 | int | |
290 | di_root_image(const char *path, char *devname, size_t devsz, dev_t *dev_p) | |
291 | { | |
292 | return di_root_image_ext(path, devname, devsz, dev_p, false); | |
293 | } | |
294 | ||
5ba3f43e A |
295 | int |
296 | di_root_ramfile_buf(void *buf, size_t bufsz, char *devname, size_t devsz, dev_t *dev_p) | |
297 | { | |
298 | IOReturn res = 0; | |
cb323159 A |
299 | IOService *controller = NULL; |
300 | OSNumber *myResult = NULL; | |
301 | OSString *myDevName = NULL; | |
302 | OSNumber *myDevT = NULL; | |
303 | IOMemoryDescriptor *mem = NULL; | |
5ba3f43e A |
304 | |
305 | mem = IOMemoryDescriptor::withAddress(buf, bufsz, kIODirectionInOut); | |
306 | assert(mem); | |
307 | ||
308 | controller = di_load_controller(); | |
309 | if (controller) { | |
310 | /* attach the image */ | |
311 | controller->setProperty(kDIRootRamFileKey, mem); | |
312 | controller->release(); | |
313 | } else { | |
314 | res = kIOReturnNotFound; | |
315 | goto out; | |
316 | } | |
317 | ||
318 | myResult = OSDynamicCast(OSNumber, controller->getProperty(kDIRootImageResultKey)); | |
319 | res = kIOReturnError; | |
320 | if (myResult) { | |
321 | res = myResult->unsigned32BitValue(); | |
322 | } | |
323 | ||
324 | if (res) { | |
325 | IOLog("%s is 0x%08X/%d\n", kDIRootImageResultKey, res, res); | |
326 | goto out; | |
327 | } | |
328 | ||
329 | myDevT = OSDynamicCast(OSNumber, controller->getProperty(kDIRootImageDevTKey)); | |
0a7de745 | 330 | if (myDevT) { |
5ba3f43e | 331 | *dev_p = myDevT->unsigned32BitValue(); |
0a7de745 | 332 | } else { |
5ba3f43e A |
333 | IOLog("could not get %s\n", kDIRootImageDevTKey); |
334 | res = kIOReturnError; | |
335 | goto out; | |
336 | } | |
337 | ||
338 | myDevName = OSDynamicCast(OSString, controller->getProperty(kDIRootImageDevNameKey)); | |
339 | if (myDevName) { | |
340 | strlcpy(devname, myDevName->getCStringNoCopy(), devsz); | |
341 | } else { | |
342 | IOLog("could not get %s\n", kDIRootImageDevNameKey); | |
343 | res = kIOReturnError; | |
344 | goto out; | |
345 | } | |
346 | ||
347 | out: | |
348 | if (res) { | |
349 | OSSafeReleaseNULL(mem); | |
350 | } | |
351 | ||
352 | return res; | |
353 | } | |
354 | ||
0a7de745 A |
355 | void |
356 | di_root_ramfile( IORegistryEntry * entry ) | |
6d2010ae | 357 | { |
0a7de745 A |
358 | OSData * data; |
359 | IOMemoryDescriptor * mem; | |
360 | uint64_t dmgSize; | |
361 | uint64_t remain, length; | |
cb323159 | 362 | OSData * extentData = NULL; |
0a7de745 A |
363 | IOAddressRange * extentList; |
364 | uint64_t extentSize; | |
365 | uint32_t extentCount; | |
366 | ||
367 | do { | |
368 | data = OSDynamicCast(OSData, entry->getProperty("boot-ramdmg-size")); | |
369 | if (!data || (data->getLength() != sizeof(uint64_t))) { | |
370 | break; // bad disk image size | |
371 | } | |
372 | dmgSize = *(uint64_t *) data->getBytesNoCopy(); | |
373 | if (!dmgSize) { | |
374 | break; | |
375 | } | |
376 | ||
377 | data = OSDynamicCast(OSData, entry->getProperty("boot-ramdmg-extents")); | |
378 | if (!data || (data->getLength() == 0) || | |
379 | ((data->getLength() & (sizeof(IOAddressRange) - 1)) != 0)) { | |
380 | break; // bad extents | |
381 | } | |
382 | // make modifications to local copy | |
383 | extentData = OSData::withData(data); | |
384 | assert(extentData); | |
385 | ||
386 | extentList = (IOAddressRange *) extentData->getBytesNoCopy(); | |
387 | extentCount = extentData->getLength() / sizeof(IOAddressRange); | |
388 | extentSize = 0; | |
389 | remain = dmgSize; | |
390 | ||
391 | // truncate extent length to enclosing disk image | |
392 | for (uint32_t i = 0; i < extentCount; i++) { | |
393 | length = extentList[i].length; | |
394 | if (!length) { | |
395 | break; | |
396 | } | |
397 | ||
398 | extentSize += length; | |
399 | if (length >= remain) { | |
400 | extentList[i].length = remain; | |
401 | extentCount = i + 1; | |
402 | break; | |
403 | } | |
404 | remain -= length; | |
405 | } | |
406 | if (extentSize < dmgSize) { | |
407 | break; // not enough extent bytes for enclosing disk image | |
408 | } | |
409 | mem = IOMemoryDescriptor::withAddressRanges( | |
410 | extentList, extentCount, | |
411 | kIODirectionOut | kIOMemoryMapperNone, NULL); | |
412 | ||
413 | if (mem) { | |
414 | IOService * controller = di_load_controller(); | |
415 | if (controller) { | |
416 | controller->setProperty(kDIRootRamFileKey, mem); | |
417 | controller->release(); | |
418 | } | |
419 | mem->release(); | |
420 | } | |
421 | } while (false); | |
422 | ||
423 | if (extentData) { | |
424 | extentData->release(); | |
425 | } | |
6d2010ae | 426 | } |
9bccf70c | 427 | }; |