1 | /* |
2 | * Copyright (c) 2002-2016 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 | /* |
29 | * DINetBootHook.c |
30 | * DiskImages |
31 | * |
32 | * Created by Byron Han on Sat Apr 13 2002. |
33 | * |
34 | * Revision History |
35 | * |
36 | * $Log: DINetBootHook.cpp,v $ |
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 | * |
41 | * Revision 1.3.1558.1 2005/06/24 01:47:25 lindak |
42 | * Bringing over all of the Karma changes into chardonnay. |
43 | * |
44 | * Revision 1.1.1.1 2005/02/24 21:48:06 akosut |
45 | * Import xnu-764 from Tiger8A395 |
46 | * |
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) |
50 | * |
51 | * Revision 1.2.40.2 2002/06/15 03:50:38 dieter |
52 | * - corrected com.apple.AppleDiskImageController.load string |
53 | * |
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 |
57 | * |
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) |
61 | * |
62 | * Revision 1.1.2.1 2002/04/24 22:29:12 dieter |
63 | * Bug #: 2909558 |
64 | * - added IOHDIXController netboot stubs |
65 | * |
66 | * Revision 1.3 2002/04/16 00:41:37 han |
67 | * migrated code out of here to IOHDIXController's setProperty method |
68 | * |
69 | * Revision 1.2 2002/04/14 23:53:53 han |
70 | * eliminate qDEBUG=1, use emums instead of hard coded string constants |
71 | * |
72 | * Revision 1.1 2002/04/14 22:54:42 han |
73 | * Renamed from DINetBookHook.c. |
74 | * First stab at implementing this code. |
75 | * |
76 | * Revision 1.1 2002/04/13 19:22:28 han |
77 | * added stub file DINetBookHook.c |
78 | * |
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> |
90 | #include <IOKit/IOService.h> |
91 | #include <IOKit/IOLib.h> |
92 | #include "DINetBootHook.h" |
93 | |
94 | #define kIOHDIXControllerClassName "IOHDIXController" |
95 | #define kDIRootImageKey "di-root-image" |
96 | #define kDIRootImageResultKey "di-root-image-result" |
97 | #define kDIRootImageDevNameKey "di-root-image-devname" |
98 | #define kDIRootImageDevTKey "di-root-image-devt" |
99 | #define kDIRootRamFileKey "di-root-ram-file" |
100 | |
101 | static IOService * |
102 | di_load_controller( void ) |
103 | { |
104 | OSIterator * controllerIterator = 0; |
105 | OSDictionary * matchDictionary = 0; |
106 | IOService * controller = 0; |
107 | |
108 | do { |
109 | IOService::getResourceService()->publishResource("com.apple.AppleDiskImageController.load" , kOSBooleanTrue); |
110 | IOService::getResourceService()->waitQuiet(); |
111 | |
112 | // first find IOHDIXController |
113 | matchDictionary = IOService::serviceMatching(kIOHDIXControllerClassName); |
114 | if (!matchDictionary) |
115 | break; |
116 | |
117 | controllerIterator = IOService::getMatchingServices(matchDictionary); |
118 | if (!controllerIterator) |
119 | break; |
120 | |
121 | controller = OSDynamicCast(IOService, controllerIterator->getNextObject()); |
122 | if (!controller) |
123 | break; |
124 | |
125 | controller->retain(); |
126 | } while (false); |
127 | |
128 | if (matchDictionary) matchDictionary->release(); |
129 | if (controllerIterator) controllerIterator->release(); |
130 | |
131 | return controller; |
132 | } |
133 | |
134 | extern "C" { |
135 | /* |
136 | Name: di_root_image |
137 | Function: mount the disk image returning the dev node |
138 | Parameters: path -> path/url to disk image |
139 | devname <- dev node used to set the rootdevice global variable |
140 | dev_p <- device number generated from major/minor numbers |
141 | Comments: |
142 | */ |
143 | int di_root_image(const char *path, char *devname, size_t devsz, dev_t *dev_p) |
144 | { |
145 | IOReturn res = 0; |
146 | IOService * controller = 0; |
147 | OSString * pathString = 0; |
148 | OSNumber * myResult = 0; |
149 | OSString * myDevName = 0; |
150 | OSNumber * myDevT = 0; |
151 | |
152 | // sanity check arguments please |
153 | if (devname) *devname = 0; |
154 | if (dev_p) *dev_p = 0; |
155 | |
156 | if (!path) return kIOReturnBadArgument; |
157 | if (!devname) return kIOReturnBadArgument; |
158 | if (!dev_p) return kIOReturnBadArgument; |
159 | |
160 | controller = di_load_controller(); |
161 | if (!controller) { |
162 | res = kIOReturnNotFound; |
163 | goto NoIOHDIXController; |
164 | } |
165 | |
166 | // okay create path object |
167 | pathString = OSString::withCString(path); |
168 | if (!pathString) { |
169 | res = kIOReturnNoMemory; |
170 | goto CannotCreatePathOSString; |
171 | } |
172 | |
173 | // do it |
174 | if (!controller->setProperty(kDIRootImageKey, pathString)) |
175 | IOLog("IOHDIXController::setProperty(%s, %s) failed.\n" , kDIRootImageKey, pathString->getCStringNoCopy()); |
176 | |
177 | myResult = OSDynamicCast(OSNumber, controller->getProperty(kDIRootImageResultKey)); |
178 | res = kIOReturnError; |
179 | if (myResult) |
180 | res = myResult->unsigned32BitValue(); |
181 | |
182 | if (res) { |
183 | IOLog("%s is 0x%08X/%d\n" , kDIRootImageResultKey, res, res); |
184 | goto di_root_image_FAILED; |
185 | } |
186 | |
187 | // success - grab |
188 | myDevT = OSDynamicCast(OSNumber, controller->getProperty(kDIRootImageDevTKey)); |
189 | if (myDevT) |
190 | *dev_p = myDevT->unsigned32BitValue(); |
191 | else { |
192 | IOLog("could not get %s\n" , kDIRootImageDevTKey); |
193 | res = kIOReturnError; |
194 | goto di_root_image_FAILED; |
195 | } |
196 | |
197 | myDevName = OSDynamicCast(OSString, controller->getProperty(kDIRootImageDevNameKey)); |
198 | if (myDevName) { |
199 | strlcpy(devname, myDevName->getCStringNoCopy(), devsz); |
200 | } else { |
201 | IOLog("could not get %s\n" , kDIRootImageDevNameKey); |
202 | res = kIOReturnError; |
203 | goto di_root_image_FAILED; |
204 | } |
205 | |
206 | |
207 | di_root_image_FAILED: |
208 | CannotCreatePathOSString: |
209 | NoIOHDIXController: |
210 | |
211 | // clean up memory allocations |
212 | if (pathString) pathString->release(); |
213 | if (controller) controller->release(); |
214 | |
215 | return res; |
216 | } |
217 | |
218 | int |
219 | di_root_ramfile_buf(void *buf, size_t bufsz, char *devname, size_t devsz, dev_t *dev_p) |
220 | { |
221 | IOReturn res = 0; |
222 | IOService *controller = 0; |
223 | OSNumber *myResult = 0; |
224 | OSString *myDevName = 0; |
225 | OSNumber *myDevT = 0; |
226 | IOMemoryDescriptor *mem = 0; |
227 | |
228 | mem = IOMemoryDescriptor::withAddress(buf, bufsz, kIODirectionInOut); |
229 | assert(mem); |
230 | |
231 | controller = di_load_controller(); |
232 | if (controller) { |
233 | /* attach the image */ |
234 | controller->setProperty(kDIRootRamFileKey, mem); |
235 | controller->release(); |
236 | } else { |
237 | res = kIOReturnNotFound; |
238 | goto out; |
239 | } |
240 | |
241 | myResult = OSDynamicCast(OSNumber, controller->getProperty(kDIRootImageResultKey)); |
242 | res = kIOReturnError; |
243 | if (myResult) { |
244 | res = myResult->unsigned32BitValue(); |
245 | } |
246 | |
247 | if (res) { |
248 | IOLog("%s is 0x%08X/%d\n" , kDIRootImageResultKey, res, res); |
249 | goto out; |
250 | } |
251 | |
252 | myDevT = OSDynamicCast(OSNumber, controller->getProperty(kDIRootImageDevTKey)); |
253 | if (myDevT) |
254 | *dev_p = myDevT->unsigned32BitValue(); |
255 | else { |
256 | IOLog("could not get %s\n" , kDIRootImageDevTKey); |
257 | res = kIOReturnError; |
258 | goto out; |
259 | } |
260 | |
261 | myDevName = OSDynamicCast(OSString, controller->getProperty(kDIRootImageDevNameKey)); |
262 | if (myDevName) { |
263 | strlcpy(devname, myDevName->getCStringNoCopy(), devsz); |
264 | } else { |
265 | IOLog("could not get %s\n" , kDIRootImageDevNameKey); |
266 | res = kIOReturnError; |
267 | goto out; |
268 | } |
269 | |
270 | out: |
271 | if (res) { |
272 | OSSafeReleaseNULL(mem); |
273 | } |
274 | |
275 | return res; |
276 | } |
277 | |
278 | void di_root_ramfile( IORegistryEntry * entry ) |
279 | { |
280 | OSData * data; |
281 | IOMemoryDescriptor * mem; |
282 | uint64_t dmgSize; |
283 | uint64_t remain, length; |
284 | OSData * extentData = 0; |
285 | IOAddressRange * extentList; |
286 | uint64_t extentSize; |
287 | uint32_t extentCount; |
288 | |
289 | do { |
290 | data = OSDynamicCast(OSData, entry->getProperty("boot-ramdmg-size" )); |
291 | if (!data || (data->getLength() != sizeof(uint64_t))) |
292 | break; // bad disk image size |
293 | |
294 | dmgSize = *(uint64_t *) data->getBytesNoCopy(); |
295 | if (!dmgSize) |
296 | break; |
297 | |
298 | data = OSDynamicCast(OSData, entry->getProperty("boot-ramdmg-extents" )); |
299 | if (!data || (data->getLength() == 0) || |
300 | ((data->getLength() & (sizeof(IOAddressRange)-1)) != 0)) |
301 | break; // bad extents |
302 | |
303 | // make modifications to local copy |
304 | extentData = OSData::withData(data); |
305 | assert(extentData); |
306 | |
307 | extentList = (IOAddressRange *) extentData->getBytesNoCopy(); |
308 | extentCount = extentData->getLength() / sizeof(IOAddressRange); |
309 | extentSize = 0; |
310 | remain = dmgSize; |
311 | |
312 | // truncate extent length to enclosing disk image |
313 | for (uint32_t i = 0; i < extentCount; i++) |
314 | { |
315 | length = extentList[i].length; |
316 | if (!length) break; |
317 | |
318 | extentSize += length; |
319 | if (length >= remain) |
320 | { |
321 | extentList[i].length = remain; |
322 | extentCount = i + 1; |
323 | break; |
324 | } |
325 | remain -= length; |
326 | } |
327 | if (extentSize < dmgSize) |
328 | break; // not enough extent bytes for enclosing disk image |
329 | |
330 | mem = IOMemoryDescriptor::withAddressRanges( |
331 | extentList, extentCount, |
332 | kIODirectionOut | kIOMemoryMapperNone, NULL); |
333 | |
334 | if (mem) |
335 | { |
336 | IOService * controller = di_load_controller(); |
337 | if (controller) |
338 | { |
339 | controller->setProperty(kDIRootRamFileKey, mem); |
340 | controller->release(); |
341 | } |
342 | mem->release(); |
343 | } |
344 | } while (false); |
345 | |
346 | if (extentData) |
347 | extentData->release(); |
348 | } |
349 | |
350 | }; |
351 | |