]>
Commit | Line | Data |
---|---|---|
04fee52e A |
1 | /* |
2 | * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
db839b1d | 6 | * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. |
04fee52e | 7 | * |
db839b1d A |
8 | * This file contains Original Code and/or Modifications of Original Code |
9 | * as defined in and that are subject to the Apple Public Source License | |
10 | * Version 2.0 (the 'License'). You may not use this file except in | |
11 | * compliance with the License. Please obtain a copy of the License at | |
12 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
13 | * file. | |
14 | * | |
15 | * The Original Code and all software distributed under the License are | |
16 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
04fee52e A |
17 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
18 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
db839b1d A |
19 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. |
20 | * Please see the License for the specific language governing rights and | |
21 | * limitations under the License. | |
04fee52e A |
22 | * |
23 | * @APPLE_LICENSE_HEADER_END@ | |
24 | */ | |
25 | /* | |
26 | * drivers.c - Driver Loading Functions. | |
27 | * | |
28 | * Copyright (c) 2000 Apple Computer, Inc. | |
29 | * | |
30 | * DRI: Josh de Cesare | |
31 | */ | |
32 | ||
33 | #include <sl.h> | |
34 | ||
71019aa0 A |
35 | #define DRIVER_DEBUG 0 |
36 | ||
04fee52e A |
37 | enum { |
38 | kTagTypeNone = 0, | |
39 | kTagTypeDict, | |
40 | kTagTypeKey, | |
41 | kTagTypeString, | |
42 | kTagTypeInteger, | |
43 | kTagTypeData, | |
44 | kTagTypeDate, | |
45 | kTagTypeFalse, | |
46 | kTagTypeTrue, | |
47 | kTagTypeArray | |
48 | }; | |
49 | ||
50 | #define kXMLTagPList "plist " | |
51 | #define kXMLTagDict "dict" | |
52 | #define kXMLTagKey "key" | |
53 | #define kXMLTagString "string" | |
54 | #define kXMLTagInteger "integer" | |
55 | #define kXMLTagData "data" | |
56 | #define kXMLTagDate "date" | |
57 | #define kXMLTagFalse "false/" | |
58 | #define kXMLTagTrue "true/" | |
59 | #define kXMLTagArray "array" | |
60 | ||
61 | #define kPropCFBundleIdentifier ("CFBundleIdentifier") | |
62 | #define kPropCFBundleExecutable ("CFBundleExecutable") | |
63 | #define kPropOSBundleRequired ("OSBundleRequired") | |
64 | #define kPropOSBundleLibraries ("OSBundleLibraries") | |
65 | #define kPropIOKitPersonalities ("IOKitPersonalities") | |
66 | #define kPropIONameMatch ("IONameMatch") | |
67 | ||
68 | struct Tag { | |
69 | long type; | |
70 | char *string; | |
71 | struct Tag *tag; | |
72 | struct Tag *tagNext; | |
73 | }; | |
74 | typedef struct Tag Tag, *TagPtr; | |
75 | ||
76 | struct Module { | |
77 | struct Module *nextModule; | |
78 | long willLoad; | |
79 | TagPtr dict; | |
80 | char *plistAddr; | |
81 | long plistLength; | |
82 | char *driverPath; | |
83 | }; | |
84 | typedef struct Module Module, *ModulePtr; | |
85 | ||
86 | struct DriverInfo { | |
87 | char *plistAddr; | |
88 | long plistLength; | |
89 | void *moduleAddr; | |
90 | long moduleLength; | |
91 | }; | |
92 | typedef struct DriverInfo DriverInfo, *DriverInfoPtr; | |
93 | ||
94 | #define kDriverPackageSignature1 'MKXT' | |
95 | #define kDriverPackageSignature2 'MOSX' | |
96 | ||
97 | struct DriversPackage { | |
98 | unsigned long signature1; | |
99 | unsigned long signature2; | |
100 | unsigned long length; | |
101 | unsigned long alder32; | |
102 | unsigned long version; | |
103 | unsigned long numDrivers; | |
104 | unsigned long reserved1; | |
105 | unsigned long reserved2; | |
106 | }; | |
107 | typedef struct DriversPackage DriversPackage; | |
108 | ||
366defd1 A |
109 | enum { |
110 | kCFBundleType2, | |
111 | kCFBundleType3 | |
112 | }; | |
113 | ||
04fee52e A |
114 | static long FileLoadDrivers(char *dirSpec, long plugin); |
115 | static long NetLoadDrivers(char *dirSpec); | |
116 | static long LoadDriverMKext(char *fileSpec); | |
366defd1 | 117 | static long LoadDriverPList(char *dirSpec, char *name, long bundleType); |
04fee52e A |
118 | static long LoadMatchedModules(void); |
119 | static long MatchPersonalities(void); | |
120 | static long MatchLibraries(void); | |
121 | static TagPtr GetProperty(TagPtr dict, char *key); | |
122 | static ModulePtr FindModule(char *name); | |
123 | static long ParseXML(char *buffer, ModulePtr *module, TagPtr *personalities); | |
124 | static long ParseNextTag(char *buffer, TagPtr *tag); | |
125 | static long ParseTagList(char *buffer, TagPtr *tag, long type, long empty); | |
126 | static long ParseTagKey(char *buffer, TagPtr *tag); | |
127 | static long ParseTagString(char *buffer, TagPtr *tag); | |
128 | static long ParseTagInteger(char *buffer, TagPtr *tag); | |
129 | static long ParseTagData(char *buffer, TagPtr *tag); | |
130 | static long ParseTagDate(char *buffer, TagPtr *tag); | |
131 | static long ParseTagBoolean(char *buffer, TagPtr *tag, long type); | |
132 | static long GetNextTag(char *buffer, char **tag, long *start); | |
133 | static long FixDataMatchingTag(char *buffer, char *tag); | |
134 | static TagPtr NewTag(void); | |
135 | static void FreeTag(TagPtr tag); | |
136 | static char *NewSymbol(char *string); | |
137 | static void FreeSymbol(char *string); | |
71019aa0 | 138 | #if DRIVER_DEBUG |
04fee52e | 139 | static void DumpTag(TagPtr tag, long depth); |
71019aa0 | 140 | #endif |
04fee52e A |
141 | |
142 | static ModulePtr gModuleHead, gModuleTail; | |
143 | static TagPtr gPersonalityHead, gPersonalityTail; | |
04fee52e A |
144 | static char gDriverSpec[4096]; |
145 | static char gFileSpec[4096]; | |
366defd1 A |
146 | static char gTempSpec[4096]; |
147 | static char gFileName[4096]; | |
04fee52e A |
148 | |
149 | // Public Functions | |
150 | ||
151 | long LoadDrivers(char *dirSpec) | |
152 | { | |
153 | if (gBootFileType == kNetworkDeviceType) { | |
154 | NetLoadDrivers(dirSpec); | |
155 | } else if (gBootFileType == kBlockDeviceType) { | |
b1faa321 | 156 | FileLoadDrivers(dirSpec, 0); |
04fee52e A |
157 | } else { |
158 | return 0; | |
159 | } | |
160 | ||
161 | MatchPersonalities(); | |
162 | ||
163 | MatchLibraries(); | |
164 | ||
165 | LoadMatchedModules(); | |
166 | ||
167 | return 0; | |
168 | } | |
169 | ||
170 | // Private Functions | |
171 | ||
172 | static long FileLoadDrivers(char *dirSpec, long plugin) | |
173 | { | |
366defd1 A |
174 | long ret, length, index, flags, time, time2, bundleType; |
175 | char *name; | |
04fee52e A |
176 | |
177 | if (!plugin) { | |
178 | ret = GetFileInfo(dirSpec, "Extensions.mkext", &flags, &time); | |
366defd1 | 179 | if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeFlat)) { |
04fee52e | 180 | ret = GetFileInfo(dirSpec, "Extensions", &flags, &time2); |
366defd1 A |
181 | if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeDirectory) || |
182 | (((gBootMode & kBootModeSafe) == 0) && (time > time2))) { | |
04fee52e A |
183 | sprintf(gDriverSpec, "%sExtensions.mkext", dirSpec); |
184 | printf("LoadDrivers: Loading from [%s]\n", gDriverSpec); | |
185 | if (LoadDriverMKext(gDriverSpec) == 0) return 0; | |
186 | } | |
187 | } | |
188 | ||
189 | strcat(dirSpec, "Extensions"); | |
190 | } | |
191 | ||
192 | printf("LoadDrivers: Loading from [%s]\n", dirSpec); | |
193 | ||
194 | index = 0; | |
195 | while (1) { | |
196 | ret = GetDirEntry(dirSpec, &index, &name, &flags, &time); | |
197 | if (ret == -1) break; | |
198 | ||
199 | // Make sure this is a directory. | |
366defd1 | 200 | if ((flags & kFileTypeMask ) != kFileTypeDirectory) continue; |
04fee52e A |
201 | |
202 | // Make sure this is a kext. | |
203 | length = strlen(name); | |
204 | if (strcmp(name + length - 5, ".kext")) continue; | |
205 | ||
366defd1 A |
206 | // Save the file name. |
207 | strcpy(gFileName, name); | |
208 | ||
209 | // Determine the bundle type. | |
210 | sprintf(gTempSpec, "%s\\%s", dirSpec, gFileName); | |
211 | ret = GetFileInfo(gTempSpec, "Contents", &flags, &time); | |
212 | if (ret == 0) bundleType = kCFBundleType2; | |
213 | else bundleType = kCFBundleType3; | |
04fee52e | 214 | |
366defd1 A |
215 | if (!plugin) { |
216 | sprintf(gDriverSpec, "%s\\%s\\%sPlugIns", dirSpec, gFileName, | |
217 | (bundleType == kCFBundleType2) ? "Contents\\" : ""); | |
218 | } | |
219 | ||
220 | ret = LoadDriverPList(dirSpec, gFileName, bundleType); | |
04fee52e A |
221 | if (ret != 0) { |
222 | printf("LoadDrivers: failed\n"); | |
223 | } | |
224 | ||
366defd1 | 225 | if (!plugin) { |
04fee52e | 226 | ret = FileLoadDrivers(gDriverSpec, 1); |
366defd1 | 227 | } |
04fee52e A |
228 | } |
229 | ||
230 | return 0; | |
231 | } | |
232 | ||
233 | ||
234 | static long NetLoadDrivers(char *dirSpec) | |
235 | { | |
236 | long tries, cnt; | |
237 | ||
238 | // Get the name of the kernel | |
239 | cnt = strlen(gBootFile); | |
240 | while (cnt--) { | |
241 | if ((gBootFile[cnt] == '\\') || (gBootFile[cnt] == ',')) { | |
242 | cnt++; | |
243 | break; | |
244 | } | |
245 | } | |
246 | ||
247 | sprintf(gDriverSpec, "%s%s.mkext", dirSpec, gBootFile + cnt); | |
248 | ||
249 | printf("NetLoadDrivers: Loading from [%s]\n", gDriverSpec); | |
250 | ||
251 | tries = 10; | |
252 | while (tries--) { | |
253 | if (LoadDriverMKext(gDriverSpec) == 0) break; | |
254 | } | |
255 | if (tries == -1) return -1; | |
256 | ||
257 | return 0; | |
258 | } | |
259 | ||
260 | ||
261 | static long LoadDriverMKext(char *fileSpec) | |
262 | { | |
71019aa0 | 263 | unsigned long driversAddr, driversLength, length; |
04fee52e A |
264 | char segName[32]; |
265 | DriversPackage *package = (DriversPackage *)kLoadAddr; | |
266 | ||
267 | // Load the MKext. | |
71019aa0 A |
268 | length = LoadFile(fileSpec); |
269 | if (length == -1) return -1; | |
270 | ||
271 | ThinFatBinary((void **)&package, &length); | |
04fee52e A |
272 | |
273 | // Verify the MKext. | |
274 | if ((package->signature1 != kDriverPackageSignature1) || | |
275 | (package->signature2 != kDriverPackageSignature2)) return -1; | |
276 | if (package->length > kLoadSize) return -1; | |
277 | if (package->alder32 != Alder32((char *)&package->version, | |
278 | package->length - 0x10)) return -1; | |
279 | ||
280 | // Make space for the MKext. | |
281 | driversLength = package->length; | |
282 | driversAddr = AllocateKernelMemory(driversLength); | |
283 | ||
284 | // Copy the MKext. | |
71019aa0 | 285 | memcpy((void *)driversAddr, (void *)package, driversLength); |
04fee52e A |
286 | |
287 | // Add the MKext to the memory map. | |
288 | sprintf(segName, "DriversPackage-%x", driversAddr); | |
289 | AllocateMemoryRange(segName, driversAddr, driversLength); | |
290 | ||
291 | return 0; | |
292 | } | |
293 | ||
294 | ||
366defd1 | 295 | static long LoadDriverPList(char *dirSpec, char *name, long bundleType) |
04fee52e A |
296 | { |
297 | long length, ret, driverPathLength; | |
298 | char *buffer; | |
299 | ModulePtr module; | |
300 | TagPtr personalities; | |
301 | char *tmpDriverPath; | |
302 | ||
366defd1 A |
303 | // Reset the malloc zone. |
304 | malloc_init((char *)kMallocAddr, kMallocSize); | |
305 | ||
04fee52e | 306 | // Save the driver path. |
366defd1 A |
307 | sprintf(gFileSpec, "%s\\%s\\%s", dirSpec, name, |
308 | (bundleType == kCFBundleType2) ? "Contents\\MacOS\\" : ""); | |
04fee52e A |
309 | driverPathLength = strlen(gFileSpec); |
310 | tmpDriverPath = malloc(driverPathLength + 1); | |
311 | if (tmpDriverPath == 0) return -1; | |
312 | strcpy(tmpDriverPath, gFileSpec); | |
313 | ||
314 | // Construct the file spec. | |
366defd1 A |
315 | sprintf(gFileSpec, "%s\\%s\\%sInfo.plist", dirSpec, name, |
316 | (bundleType == kCFBundleType2) ? "Contents\\" : ""); | |
04fee52e A |
317 | |
318 | length = LoadFile(gFileSpec); | |
319 | if (length == -1) { | |
320 | free(tmpDriverPath); | |
321 | return -1; | |
322 | } | |
323 | ||
324 | buffer = malloc(length + 1); | |
325 | if (buffer == 0) { | |
326 | free(tmpDriverPath); | |
327 | return -1; | |
328 | } | |
329 | strncpy(buffer, (char *)kLoadAddr, length); | |
330 | ||
331 | ret = ParseXML(buffer, &module, &personalities); | |
332 | free(buffer); | |
333 | if (ret != 0) { | |
334 | free(tmpDriverPath); | |
335 | return -1; | |
336 | } | |
337 | ||
338 | // Allocate memory for the driver path and the plist. | |
339 | module->driverPath = AllocateBootXMemory(driverPathLength + 1); | |
340 | module->plistAddr = AllocateBootXMemory(length + 1); | |
341 | ||
342 | if ((module->driverPath == 0) | (module->plistAddr == 0)) { | |
343 | free(tmpDriverPath); | |
344 | return -1; | |
345 | } | |
346 | ||
347 | // Save the driver path in the module. | |
348 | strcpy(module->driverPath, tmpDriverPath); | |
349 | free(tmpDriverPath); | |
350 | ||
351 | // Add the origin plist to the module. | |
352 | strncpy(module->plistAddr, (char *)kLoadAddr, length); | |
353 | module->plistLength = length + 1; | |
354 | ||
355 | // Add the module to the end of the module list. | |
356 | if (gModuleHead == 0) gModuleHead = module; | |
357 | else gModuleTail->nextModule = module; | |
358 | gModuleTail = module; | |
359 | ||
360 | // Add the persionalities to the personality list. | |
361 | if (personalities) personalities = personalities->tag; | |
362 | while (personalities != 0) { | |
363 | if (gPersonalityHead == 0) gPersonalityHead = personalities->tag; | |
364 | else gPersonalityTail->tagNext = personalities->tag; | |
365 | gPersonalityTail = personalities->tag; | |
366 | ||
367 | personalities = personalities->tagNext; | |
368 | } | |
369 | ||
370 | return 0; | |
371 | } | |
372 | ||
373 | ||
374 | static long LoadMatchedModules(void) | |
375 | { | |
376 | TagPtr prop; | |
377 | ModulePtr module; | |
378 | char *fileName, segName[32]; | |
379 | DriverInfoPtr driver; | |
71019aa0 A |
380 | unsigned long length, driverAddr, driverLength; |
381 | void *driverModuleAddr; | |
04fee52e A |
382 | |
383 | module = gModuleHead; | |
384 | while (module != 0) { | |
385 | if (module->willLoad) { | |
386 | prop = GetProperty(module->dict, kPropCFBundleExecutable); | |
387 | if (prop != 0) { | |
388 | fileName = prop->string; | |
389 | sprintf(gFileSpec, "%s%s", module->driverPath, fileName); | |
390 | length = LoadFile(gFileSpec); | |
391 | } else length = 0; | |
392 | if (length != -1) { | |
71019aa0 A |
393 | if (length != 0) { |
394 | driverModuleAddr = (void *)kLoadAddr; | |
395 | ThinFatBinary(&driverModuleAddr, &length); | |
396 | } | |
397 | ||
04fee52e A |
398 | // Make make in the image area. |
399 | driverLength = sizeof(DriverInfo) + module->plistLength + length; | |
400 | driverAddr = AllocateKernelMemory(driverLength); | |
401 | ||
402 | // Set up the DriverInfo. | |
403 | driver = (DriverInfoPtr)driverAddr; | |
404 | driver->plistAddr = (char *)(driverAddr + sizeof(DriverInfo)); | |
405 | driver->plistLength = module->plistLength; | |
406 | if (length != 0) { | |
407 | driver->moduleAddr = (void *)(driverAddr + sizeof(DriverInfo) + | |
408 | module->plistLength); | |
409 | driver->moduleLength = length; | |
410 | } else { | |
411 | driver->moduleAddr = 0; | |
412 | driver->moduleLength = 0; | |
413 | } | |
414 | ||
415 | // Save the plist and module. | |
416 | strcpy(driver->plistAddr, module->plistAddr); | |
417 | if (length != 0) { | |
71019aa0 | 418 | memcpy(driver->moduleAddr, driverModuleAddr, driver->moduleLength); |
04fee52e A |
419 | } |
420 | ||
421 | // Add an entry to the memory map. | |
422 | sprintf(segName, "Driver-%x", driver); | |
423 | AllocateMemoryRange(segName, driverAddr, driverLength); | |
424 | } | |
425 | } | |
426 | ||
427 | module = module->nextModule; | |
428 | } | |
429 | ||
430 | return 0; | |
431 | } | |
432 | ||
433 | ||
434 | static long MatchPersonalities(void) | |
435 | { | |
436 | TagPtr persionality; | |
437 | TagPtr prop; | |
438 | ModulePtr module; | |
439 | CICell ph; | |
440 | ||
441 | // Try to match each of the personalities. | |
442 | for(persionality = gPersonalityHead; persionality != 0; | |
443 | persionality = persionality->tagNext) { | |
444 | // Get the module name. Make sure it exists and has not | |
445 | // already been marked for loading. | |
446 | prop = GetProperty(persionality, kPropCFBundleIdentifier); | |
447 | if (prop == 0) continue; | |
448 | module = FindModule(prop->string); | |
449 | if (module == 0) continue; | |
450 | if (module->willLoad) continue; | |
451 | ||
452 | // Look for the exact match property. | |
453 | // Try to match with it. | |
454 | ||
455 | // Look for the old match property. | |
456 | // Try to match with it. | |
457 | ph = 0; | |
458 | prop = GetProperty(persionality, kPropIONameMatch); | |
459 | if ((prop != 0) && (prop->tag != 0)) prop = prop->tag; | |
460 | while (prop != 0) { | |
461 | ph = SearchForNodeMatching(0, 1, prop->string); | |
462 | if (ph != 0) break; | |
463 | ||
464 | prop = prop->tagNext; | |
465 | } | |
466 | ||
467 | // If a node was found mark the module to be loaded. | |
468 | if (ph != 0) { | |
469 | module->willLoad = 1; | |
470 | } | |
471 | } | |
472 | ||
473 | return 0; | |
474 | } | |
475 | ||
476 | ||
477 | static long MatchLibraries(void) | |
478 | { | |
479 | TagPtr prop, prop2; | |
480 | ModulePtr module, module2; | |
481 | long done; | |
482 | ||
483 | do { | |
484 | done = 1; | |
485 | module = gModuleHead; | |
486 | while (module != 0) { | |
487 | if (module->willLoad == 1) { | |
488 | prop = GetProperty(module->dict, kPropOSBundleLibraries); | |
489 | if (prop != 0) { | |
490 | prop = prop->tag; | |
491 | while (prop != 0) { | |
492 | module2 = gModuleHead; | |
493 | while (module2 != 0) { | |
494 | prop2 = GetProperty(module2->dict, kPropCFBundleIdentifier); | |
495 | if ((prop2 != 0) && (!strcmp(prop->string, prop2->string))) { | |
496 | if (module2->willLoad == 0) module2->willLoad = 1; | |
497 | break; | |
498 | } | |
499 | module2 = module2->nextModule; | |
500 | } | |
501 | prop = prop->tagNext; | |
502 | } | |
503 | } | |
504 | module->willLoad = 2; | |
505 | done = 0; | |
506 | } | |
507 | module = module->nextModule; | |
508 | } | |
509 | } while (!done); | |
510 | ||
511 | return 0; | |
512 | } | |
513 | ||
514 | ||
515 | static TagPtr GetProperty(TagPtr dict, char *key) | |
516 | { | |
517 | TagPtr tagList, tag; | |
518 | ||
519 | if (dict->type != kTagTypeDict) return 0; | |
520 | ||
521 | tag = 0; | |
522 | tagList = dict->tag; | |
523 | while (tagList) { | |
524 | tag = tagList; | |
525 | tagList = tag->tagNext; | |
526 | ||
527 | if ((tag->type != kTagTypeKey) || (tag->string == 0)) continue; | |
528 | ||
529 | if (!strcmp(tag->string, key)) return tag->tag; | |
530 | } | |
531 | ||
532 | return 0; | |
533 | } | |
534 | ||
535 | ||
536 | static ModulePtr FindModule(char *name) | |
537 | { | |
538 | ModulePtr module; | |
539 | TagPtr prop; | |
540 | ||
541 | module = gModuleHead; | |
542 | ||
543 | while (module != 0) { | |
544 | prop = GetProperty(module->dict, kPropCFBundleIdentifier); | |
545 | if ((prop != 0) && !strcmp(name, prop->string)) break; | |
546 | module = module->nextModule; | |
547 | } | |
548 | ||
549 | return module; | |
550 | } | |
551 | ||
552 | ||
553 | static long ParseXML(char *buffer, ModulePtr *module, TagPtr *personalities) | |
554 | { | |
555 | long length, pos; | |
556 | TagPtr moduleDict, required; | |
557 | ModulePtr tmpModule; | |
558 | ||
559 | pos = 0; | |
560 | while (1) { | |
561 | length = ParseNextTag(buffer + pos, &moduleDict); | |
562 | if (length == -1) break; | |
563 | pos += length; | |
564 | ||
565 | if (moduleDict == 0) continue; | |
566 | ||
567 | if (moduleDict->type == kTagTypeDict) break; | |
568 | ||
569 | FreeTag(moduleDict); | |
570 | } | |
571 | ||
572 | if (length == -1) return -1; | |
573 | ||
574 | required = GetProperty(moduleDict, kPropOSBundleRequired); | |
575 | if ((required == 0) || (required->type != kTagTypeString) || | |
576 | !strcmp(required->string, "Safe Boot")) { | |
577 | FreeTag(moduleDict); | |
578 | return -1; | |
579 | } | |
580 | ||
581 | tmpModule = AllocateBootXMemory(sizeof(Module)); | |
582 | if (tmpModule == 0) { | |
583 | FreeTag(moduleDict); | |
584 | return -1; | |
585 | } | |
586 | tmpModule->dict = moduleDict; | |
587 | ||
588 | // For now, load any module that has OSBundleRequired != "Safe Boot". | |
589 | tmpModule->willLoad = 1; | |
590 | ||
591 | *module = tmpModule; | |
592 | ||
593 | // Get the personalities. | |
594 | *personalities = GetProperty(moduleDict, kPropIOKitPersonalities); | |
595 | ||
596 | return 0; | |
597 | } | |
598 | ||
599 | ||
600 | static long ParseNextTag(char *buffer, TagPtr *tag) | |
601 | { | |
602 | long length, pos; | |
603 | char *tagName; | |
604 | ||
605 | length = GetNextTag(buffer, &tagName, 0); | |
606 | if (length == -1) return -1; | |
607 | ||
608 | pos = length; | |
609 | if (!strncmp(tagName, kXMLTagPList, 6)) { | |
610 | length = 0; | |
611 | } else if (!strcmp(tagName, kXMLTagDict)) { | |
612 | length = ParseTagList(buffer + pos, tag, kTagTypeDict, 0); | |
613 | } else if (!strcmp(tagName, kXMLTagDict "/")) { | |
614 | length = ParseTagList(buffer + pos, tag, kTagTypeDict, 1); | |
615 | } else if (!strcmp(tagName, kXMLTagKey)) { | |
616 | length = ParseTagKey(buffer + pos, tag); | |
617 | } else if (!strcmp(tagName, kXMLTagString)) { | |
618 | length = ParseTagString(buffer + pos, tag); | |
619 | } else if (!strcmp(tagName, kXMLTagInteger)) { | |
620 | length = ParseTagInteger(buffer + pos, tag); | |
621 | } else if (!strcmp(tagName, kXMLTagData)) { | |
622 | length = ParseTagData(buffer + pos, tag); | |
623 | } else if (!strcmp(tagName, kXMLTagDate)) { | |
624 | length = ParseTagDate(buffer + pos, tag); | |
625 | } else if (!strcmp(tagName, kXMLTagFalse)) { | |
626 | length = ParseTagBoolean(buffer + pos, tag, kTagTypeFalse); | |
627 | } else if (!strcmp(tagName, kXMLTagTrue)) { | |
628 | length = ParseTagBoolean(buffer + pos, tag, kTagTypeTrue); | |
629 | } else if (!strcmp(tagName, kXMLTagArray)) { | |
630 | length = ParseTagList(buffer + pos, tag, kTagTypeArray, 0); | |
631 | } else if (!strcmp(tagName, kXMLTagArray "/")) { | |
632 | length = ParseTagList(buffer + pos, tag, kTagTypeArray, 1); | |
633 | } else { | |
634 | *tag = 0; | |
635 | length = 0; | |
636 | } | |
637 | ||
638 | if (length == -1) return -1; | |
639 | ||
640 | return pos + length; | |
641 | } | |
642 | ||
643 | ||
644 | static long ParseTagList(char *buffer, TagPtr *tag, long type, long empty) | |
645 | { | |
646 | long length, pos; | |
647 | TagPtr tagList, tmpTag; | |
648 | ||
649 | tagList = 0; | |
650 | pos = 0; | |
651 | ||
652 | if (!empty) { | |
653 | while (1) { | |
654 | length = ParseNextTag(buffer + pos, &tmpTag); | |
655 | if (length == -1) break; | |
656 | pos += length; | |
657 | ||
658 | if (tmpTag == 0) break; | |
659 | tmpTag->tagNext = tagList; | |
660 | tagList = tmpTag; | |
661 | } | |
662 | ||
663 | if (length == -1) { | |
664 | FreeTag(tagList); | |
665 | return -1; | |
666 | } | |
667 | } | |
668 | ||
669 | tmpTag = NewTag(); | |
670 | if (tmpTag == 0) { | |
671 | FreeTag(tagList); | |
672 | return -1; | |
673 | } | |
674 | ||
675 | tmpTag->type = type; | |
676 | tmpTag->string = 0; | |
677 | tmpTag->tag = tagList; | |
678 | tmpTag->tagNext = 0; | |
679 | ||
680 | *tag = tmpTag; | |
681 | ||
682 | return pos; | |
683 | } | |
684 | ||
685 | ||
686 | static long ParseTagKey(char *buffer, TagPtr *tag) | |
687 | { | |
688 | long length, length2; | |
689 | char *string; | |
690 | TagPtr tmpTag, subTag; | |
691 | ||
692 | length = FixDataMatchingTag(buffer, kXMLTagKey); | |
693 | if (length == -1) return -1; | |
694 | ||
695 | length2 = ParseNextTag(buffer + length, &subTag); | |
696 | if (length2 == -1) return -1; | |
697 | ||
698 | tmpTag = NewTag(); | |
699 | if (tmpTag == 0) { | |
700 | FreeTag(subTag); | |
701 | return -1; | |
702 | } | |
703 | ||
704 | string = NewSymbol(buffer); | |
705 | if (string == 0) { | |
706 | FreeTag(subTag); | |
707 | FreeTag(tmpTag); | |
708 | return -1; | |
709 | } | |
710 | ||
711 | tmpTag->type = kTagTypeKey; | |
712 | tmpTag->string = string; | |
713 | tmpTag->tag = subTag; | |
714 | tmpTag->tagNext = 0; | |
715 | ||
716 | *tag = tmpTag; | |
717 | ||
718 | return length + length2; | |
719 | } | |
720 | ||
721 | ||
722 | static long ParseTagString(char *buffer, TagPtr *tag) | |
723 | { | |
724 | long length; | |
725 | char *string; | |
726 | TagPtr tmpTag; | |
727 | ||
728 | length = FixDataMatchingTag(buffer, kXMLTagString); | |
729 | if (length == -1) return -1; | |
730 | ||
731 | tmpTag = NewTag(); | |
732 | if (tmpTag == 0) return -1; | |
733 | ||
734 | string = NewSymbol(buffer); | |
735 | if (string == 0) { | |
736 | FreeTag(tmpTag); | |
737 | return -1; | |
738 | } | |
739 | ||
740 | tmpTag->type = kTagTypeString; | |
741 | tmpTag->string = string; | |
742 | tmpTag->tag = 0; | |
743 | tmpTag->tagNext = 0; | |
744 | ||
745 | *tag = tmpTag; | |
746 | ||
747 | return length; | |
748 | } | |
749 | ||
750 | ||
751 | static long ParseTagInteger(char *buffer, TagPtr *tag) | |
752 | { | |
753 | long length, integer; | |
754 | TagPtr tmpTag; | |
755 | ||
756 | length = FixDataMatchingTag(buffer, kXMLTagInteger); | |
757 | if (length == -1) return -1; | |
758 | ||
759 | tmpTag = NewTag(); | |
760 | if (tmpTag == 0) return -1; | |
761 | ||
762 | integer = 0; | |
763 | ||
764 | tmpTag->type = kTagTypeInteger; | |
765 | tmpTag->string = (char *)integer; | |
766 | tmpTag->tag = 0; | |
767 | tmpTag->tagNext = 0; | |
768 | ||
769 | *tag = tmpTag; | |
770 | ||
771 | return length; | |
772 | } | |
773 | ||
774 | ||
775 | static long ParseTagData(char *buffer, TagPtr *tag) | |
776 | { | |
777 | long length; | |
778 | TagPtr tmpTag; | |
779 | ||
780 | length = FixDataMatchingTag(buffer, kXMLTagData); | |
781 | if (length == -1) return -1; | |
782 | ||
783 | tmpTag = NewTag(); | |
784 | if (tmpTag == 0) return -1; | |
785 | ||
786 | tmpTag->type = kTagTypeData; | |
787 | tmpTag->string = 0; | |
788 | tmpTag->tag = 0; | |
789 | tmpTag->tagNext = 0; | |
790 | ||
791 | *tag = tmpTag; | |
792 | ||
793 | return length; | |
794 | } | |
795 | ||
796 | ||
797 | static long ParseTagDate(char *buffer, TagPtr *tag) | |
798 | { | |
799 | long length; | |
800 | TagPtr tmpTag; | |
801 | ||
802 | length = FixDataMatchingTag(buffer, kXMLTagDate); | |
803 | if (length == -1) return -1; | |
804 | ||
805 | tmpTag = NewTag(); | |
806 | if (tmpTag == 0) return -1; | |
807 | ||
808 | tmpTag->type = kTagTypeDate; | |
809 | tmpTag->string = 0; | |
810 | tmpTag->tag = 0; | |
811 | tmpTag->tagNext = 0; | |
812 | ||
813 | *tag = tmpTag; | |
814 | ||
815 | return length; | |
816 | } | |
817 | ||
818 | ||
819 | static long ParseTagBoolean(char *buffer, TagPtr *tag, long type) | |
820 | { | |
821 | TagPtr tmpTag; | |
822 | ||
823 | tmpTag = NewTag(); | |
824 | if (tmpTag == 0) return -1; | |
825 | ||
826 | tmpTag->type = type; | |
827 | tmpTag->string = 0; | |
828 | tmpTag->tag = 0; | |
829 | tmpTag->tagNext = 0; | |
830 | ||
831 | *tag = tmpTag; | |
832 | ||
833 | return 0; | |
834 | } | |
835 | ||
836 | ||
837 | static long GetNextTag(char *buffer, char **tag, long *start) | |
838 | { | |
839 | long cnt, cnt2; | |
840 | ||
841 | if (tag == 0) return -1; | |
842 | ||
843 | // Find the start of the tag. | |
844 | cnt = 0; | |
845 | while ((buffer[cnt] != '\0') && (buffer[cnt] != '<')) cnt++; | |
846 | if (buffer[cnt] == '\0') return -1; | |
847 | ||
848 | // Find the end of the tag. | |
849 | cnt2 = cnt + 1; | |
850 | while ((buffer[cnt2] != '\0') && (buffer[cnt2] != '>')) cnt2++; | |
851 | if (buffer[cnt2] == '\0') return -1; | |
852 | ||
853 | // Fix the tag data. | |
854 | *tag = buffer + cnt + 1; | |
855 | buffer[cnt2] = '\0'; | |
856 | if (start) *start = cnt; | |
857 | ||
858 | return cnt2 + 1; | |
859 | } | |
860 | ||
861 | ||
862 | static long FixDataMatchingTag(char *buffer, char *tag) | |
863 | { | |
864 | long length, start, stop; | |
865 | char *endTag; | |
866 | ||
867 | start = 0; | |
868 | while (1) { | |
869 | length = GetNextTag(buffer + start, &endTag, &stop); | |
870 | if (length == -1) return -1; | |
871 | ||
872 | if ((*endTag == '/') && !strcmp(endTag + 1, tag)) break; | |
873 | start += length; | |
874 | } | |
875 | ||
876 | buffer[start + stop] = '\0'; | |
877 | ||
878 | return start + length; | |
879 | } | |
880 | ||
881 | ||
882 | #define kTagsPerBlock (0x1000) | |
883 | ||
884 | static TagPtr gTagsFree; | |
885 | ||
886 | static TagPtr NewTag(void) | |
887 | { | |
888 | long cnt; | |
889 | TagPtr tag; | |
890 | ||
891 | if (gTagsFree == 0) { | |
892 | tag = (TagPtr)AllocateBootXMemory(kTagsPerBlock * sizeof(Tag)); | |
893 | if (tag == 0) return 0; | |
894 | ||
895 | // Initalize the new tags. | |
896 | for (cnt = 0; cnt < kTagsPerBlock; cnt++) { | |
897 | tag[cnt].type = kTagTypeNone; | |
898 | tag[cnt].string = 0; | |
899 | tag[cnt].tag = 0; | |
900 | tag[cnt].tagNext = tag + cnt + 1; | |
901 | } | |
902 | tag[kTagsPerBlock - 1].tagNext = 0; | |
903 | ||
904 | gTagsFree = tag; | |
905 | } | |
906 | ||
907 | tag = gTagsFree; | |
908 | gTagsFree = tag->tagNext; | |
909 | ||
910 | return tag; | |
911 | } | |
912 | ||
913 | ||
914 | static void FreeTag(TagPtr tag) | |
915 | { | |
916 | return; | |
917 | if (tag == 0) return; | |
918 | ||
919 | if (tag->string) FreeSymbol(tag->string); | |
920 | ||
921 | FreeTag(tag->tag); | |
922 | FreeTag(tag->tagNext); | |
923 | ||
924 | // Clear and free the tag. | |
925 | tag->type = kTagTypeNone; | |
926 | tag->string = 0; | |
927 | tag->tag = 0; | |
928 | tag->tagNext = gTagsFree; | |
929 | gTagsFree = tag; | |
930 | } | |
931 | ||
932 | ||
933 | struct Symbol { | |
934 | long refCount; | |
935 | struct Symbol *next; | |
936 | char string[1]; | |
937 | }; | |
938 | typedef struct Symbol Symbol, *SymbolPtr; | |
939 | ||
940 | static SymbolPtr FindSymbol(char *string, SymbolPtr *prevSymbol); | |
941 | ||
942 | static SymbolPtr gSymbolsHead; | |
943 | ||
944 | ||
945 | static char *NewSymbol(char *string) | |
946 | { | |
947 | SymbolPtr symbol; | |
948 | ||
949 | // Look for string in the list of symbols. | |
950 | symbol = FindSymbol(string, 0); | |
951 | ||
952 | // Add the new symbol. | |
953 | if (symbol == 0) { | |
954 | symbol = AllocateBootXMemory(sizeof(Symbol) + strlen(string)); | |
955 | if (symbol == 0) return 0; | |
956 | ||
957 | // Set the symbol's data. | |
958 | symbol->refCount = 0; | |
959 | strcpy(symbol->string, string); | |
960 | ||
961 | // Add the symbol to the list. | |
962 | symbol->next = gSymbolsHead; | |
963 | gSymbolsHead = symbol; | |
964 | } | |
965 | ||
966 | // Update the refCount and return the string. | |
967 | symbol->refCount++; | |
968 | return symbol->string; | |
969 | } | |
970 | ||
971 | ||
972 | static void FreeSymbol(char *string) | |
973 | { | |
974 | #if 0 | |
975 | SymbolPtr symbol, prev; | |
976 | ||
977 | // Look for string in the list of symbols. | |
978 | symbol = FindSymbol(string, &prev); | |
979 | if (symbol == 0) return; | |
980 | ||
981 | // Update the refCount. | |
982 | symbol->refCount--; | |
983 | ||
984 | if (symbol->refCount != 0) return; | |
985 | ||
986 | // Remove the symbol from the list. | |
987 | if (prev != 0) prev->next = symbol->next; | |
988 | else gSymbolsHead = symbol->next; | |
989 | ||
990 | // Free the symbol's memory. | |
991 | free(symbol); | |
992 | #endif | |
993 | } | |
994 | ||
995 | ||
996 | static SymbolPtr FindSymbol(char *string, SymbolPtr *prevSymbol) | |
997 | { | |
998 | SymbolPtr symbol, prev; | |
999 | ||
1000 | symbol = gSymbolsHead; | |
1001 | prev = 0; | |
1002 | ||
1003 | while (symbol != 0) { | |
1004 | if (!strcmp(symbol->string, string)) break; | |
1005 | ||
1006 | prev = symbol; | |
1007 | symbol = symbol->next; | |
1008 | } | |
1009 | ||
1010 | if ((symbol != 0) && (prevSymbol != 0)) *prevSymbol = prev; | |
1011 | ||
1012 | return symbol; | |
1013 | } | |
1014 | ||
71019aa0 | 1015 | #if DRIVER_DEBUG |
04fee52e A |
1016 | static void DumpTagDict(TagPtr tag, long depth); |
1017 | static void DumpTagKey(TagPtr tag, long depth); | |
1018 | static void DumpTagString(TagPtr tag, long depth); | |
1019 | static void DumpTagInteger(TagPtr tag, long depth); | |
1020 | static void DumpTagData(TagPtr tag, long depth); | |
1021 | static void DumpTagDate(TagPtr tag, long depth); | |
1022 | static void DumpTagBoolean(TagPtr tag, long depth); | |
1023 | static void DumpTagArray(TagPtr tag, long depth); | |
1024 | static void DumpSpaces(long depth); | |
1025 | ||
1026 | static void DumpTag(TagPtr tag, long depth) | |
1027 | { | |
1028 | if (tag == 0) return; | |
1029 | ||
1030 | switch (tag->type) { | |
1031 | case kTagTypeDict : | |
1032 | DumpTagDict(tag, depth); | |
1033 | break; | |
1034 | ||
1035 | case kTagTypeKey : | |
1036 | DumpTagKey(tag, depth); | |
1037 | break; | |
1038 | ||
1039 | case kTagTypeString : | |
1040 | DumpTagString(tag, depth); | |
1041 | break; | |
1042 | ||
1043 | case kTagTypeInteger : | |
1044 | DumpTagInteger(tag, depth); | |
1045 | break; | |
1046 | ||
1047 | case kTagTypeData : | |
1048 | DumpTagData(tag, depth); | |
1049 | break; | |
1050 | ||
1051 | case kTagTypeDate : | |
1052 | DumpTagDate(tag, depth); | |
1053 | break; | |
1054 | ||
1055 | case kTagTypeFalse : | |
1056 | case kTagTypeTrue : | |
1057 | DumpTagBoolean(tag, depth); | |
1058 | break; | |
1059 | ||
1060 | case kTagTypeArray : | |
1061 | DumpTagArray(tag, depth); | |
1062 | break; | |
1063 | ||
1064 | default : | |
1065 | break; | |
1066 | } | |
1067 | } | |
1068 | ||
1069 | ||
1070 | static void DumpTagDict(TagPtr tag, long depth) | |
1071 | { | |
1072 | TagPtr tagList; | |
1073 | ||
1074 | if (tag->tag == 0) { | |
1075 | DumpSpaces(depth); | |
1076 | printf("<%s/>\n", kXMLTagDict); | |
1077 | } else { | |
1078 | DumpSpaces(depth); | |
1079 | printf("<%s>\n", kXMLTagDict); | |
1080 | ||
1081 | tagList = tag->tag; | |
1082 | while (tagList) { | |
1083 | DumpTag(tagList, depth + 1); | |
1084 | tagList = tagList->tagNext; | |
1085 | } | |
1086 | ||
1087 | DumpSpaces(depth); | |
1088 | printf("</%s>\n", kXMLTagDict); | |
1089 | } | |
1090 | } | |
1091 | ||
1092 | ||
1093 | static void DumpTagKey(TagPtr tag, long depth) | |
1094 | { | |
1095 | DumpSpaces(depth); | |
1096 | printf("<%s>%s</%s>\n", kXMLTagKey, tag->string, kXMLTagKey); | |
1097 | ||
1098 | DumpTag(tag->tag, depth); | |
1099 | } | |
1100 | ||
1101 | ||
1102 | static void DumpTagString(TagPtr tag, long depth) | |
1103 | { | |
1104 | DumpSpaces(depth); | |
1105 | printf("<%s>%s</%s>\n", kXMLTagString, tag->string, kXMLTagString); | |
1106 | } | |
1107 | ||
1108 | ||
1109 | static void DumpTagInteger(TagPtr tag, long depth) | |
1110 | { | |
1111 | DumpSpaces(depth); | |
1112 | printf("<%s>%x</%s>\n", kXMLTagInteger, tag->string, kXMLTagInteger); | |
1113 | } | |
1114 | ||
1115 | ||
1116 | static void DumpTagData(TagPtr tag, long depth) | |
1117 | { | |
1118 | DumpSpaces(depth); | |
1119 | printf("<%s>%x</%s>\n", kXMLTagData, tag->string, kXMLTagData); | |
1120 | } | |
1121 | ||
1122 | ||
1123 | static void DumpTagDate(TagPtr tag, long depth) | |
1124 | { | |
1125 | DumpSpaces(depth); | |
1126 | printf("<%s>%x</%s>\n", kXMLTagDate, tag->string, kXMLTagDate); | |
1127 | } | |
1128 | ||
1129 | ||
1130 | static void DumpTagBoolean(TagPtr tag, long depth) | |
1131 | { | |
1132 | DumpSpaces(depth); | |
1133 | printf("<%s>\n", (tag->type == kTagTypeTrue) ? kXMLTagTrue : kXMLTagFalse); | |
1134 | } | |
1135 | ||
1136 | ||
1137 | static void DumpTagArray(TagPtr tag, long depth) | |
1138 | { | |
1139 | TagPtr tagList; | |
1140 | ||
1141 | if (tag->tag == 0) { | |
1142 | DumpSpaces(depth); | |
1143 | printf("<%s/>\n", kXMLTagArray); | |
1144 | } else { | |
1145 | DumpSpaces(depth); | |
1146 | printf("<%s>\n", kXMLTagArray); | |
1147 | ||
1148 | tagList = tag->tag; | |
1149 | while (tagList) { | |
1150 | DumpTag(tagList, depth + 1); | |
1151 | tagList = tagList->tagNext; | |
1152 | } | |
1153 | ||
1154 | DumpSpaces(depth); | |
1155 | printf("</%s>\n", kXMLTagArray); | |
1156 | } | |
1157 | } | |
1158 | ||
1159 | ||
1160 | static void DumpSpaces(long depth) | |
1161 | { | |
1162 | long cnt; | |
1163 | ||
1164 | for (cnt = 0; cnt < (depth * 4); cnt++) putchar(' '); | |
1165 | } | |
1166 | #endif |