]>
Commit | Line | Data |
---|---|---|
1815bff5 | 1 | /* |
cf37c299 | 2 | * Copyright (c) 2000-2016 Apple Inc. All rights reserved. |
1815bff5 A |
3 | * |
4 | * @APPLE_LICENSE_HEADER_START@ | |
2fc1e207 A |
5 | * |
6 | * The contents of this file constitute Original Code as defined in and | |
7 | * are subject to the Apple Public Source License Version 1.1 (the | |
8 | * "License"). You may not use this file except in compliance with the | |
9 | * License. Please obtain a copy of the License at | |
10 | * http://www.apple.com/publicsource and read it before using this file. | |
11 | * | |
12 | * This Original Code and all software distributed under the License are | |
13 | * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
1815bff5 A |
14 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
15 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
2fc1e207 A |
16 | * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the |
17 | * License for the specific language governing rights and limitations | |
18 | * under the License. | |
19 | * | |
1815bff5 A |
20 | * @APPLE_LICENSE_HEADER_END@ |
21 | */ | |
22 | /* | |
83f6dbe8 | 23 | cc -o nvram nvram.c -framework CoreFoundation -framework IOKit -Wall |
1815bff5 A |
24 | */ |
25 | ||
26 | #include <stdio.h> | |
27 | #include <IOKit/IOKitLib.h> | |
83f6dbe8 | 28 | #include <IOKit/IOKitKeys.h> |
9726c137 | 29 | #include <IOKit/IOKitKeysPrivate.h> |
1815bff5 | 30 | #include <CoreFoundation/CoreFoundation.h> |
ef8ad44b A |
31 | #include <err.h> |
32 | #include <mach/mach_error.h> | |
cf37c299 | 33 | #include <sys/stat.h> |
1815bff5 A |
34 | |
35 | // Prototypes | |
1815bff5 A |
36 | static void UsageMessage(char *message); |
37 | static void ParseFile(char *fileName); | |
34d340d7 | 38 | static void ParseXMLFile(char *fileName); |
1815bff5 A |
39 | static void SetOrGetOFVariable(char *str); |
40 | static kern_return_t GetOFVariable(char *name, CFStringRef *nameRef, | |
41 | CFTypeRef *valueRef); | |
42 | static kern_return_t SetOFVariable(char *name, char *value); | |
83f6dbe8 | 43 | static void DeleteOFVariable(char *name); |
1815bff5 A |
44 | static void PrintOFVariables(void); |
45 | static void PrintOFVariable(const void *key,const void *value,void *context); | |
34d340d7 A |
46 | static void SetOFVariableFromFile(const void *key, const void *value, void *context); |
47 | static void ClearOFVariables(void); | |
48 | static void ClearOFVariable(const void *key,const void *value,void *context); | |
1815bff5 A |
49 | static CFTypeRef ConvertValueToCFTypeRef(CFTypeID typeID, char *value); |
50 | ||
8459d725 A |
51 | static void NVRamSyncNow(char *name); |
52 | ||
1815bff5 A |
53 | // Global Variables |
54 | static char *gToolName; | |
55 | static io_registry_entry_t gOptionsRef; | |
34d340d7 | 56 | static bool gUseXML; |
9726c137 | 57 | static bool gUseForceSync; |
1815bff5 | 58 | |
c00fdd17 A |
59 | #if TARGET_OS_BRIDGE /* Stuff for nvram bridge -> intel */ |
60 | #include <dlfcn.h> | |
61 | #include <libMacEFIManager/MacEFIHostInterfaceAPI.h> | |
62 | ||
63 | static kern_return_t LinkMacNVRAMSymbols(void); | |
64 | static kern_return_t GetMacOFVariable(char *name, char **value); | |
65 | static kern_return_t SetMacOFVariable(char *name, char *value); | |
919ea02d | 66 | static kern_return_t DeleteMacOFVariable(char *name); |
c00fdd17 A |
67 | |
68 | static bool gBridgeToIntel; | |
69 | static void *gDL_handle; | |
70 | static void *gNvramInterface; | |
71 | ||
72 | static void (*hostInterfaceInitialize_fptr)(void); | |
73 | static void *(*createNvramHostInterface_fptr)(const char *handle); | |
74 | static kern_return_t (*destroyNvramHostInterface_fptr)(void *interface); | |
75 | static kern_return_t (*getNVRAMVariable_fptr)(void *interface, char *name, char **buffer, uint32_t *size); | |
919ea02d A |
76 | static kern_return_t (*setNVRAMVariable_fptr)(void *interface, char *name, char *buffer); |
77 | static kern_return_t (*deleteNVRAMVariable_fptr)(void *interface, char *name); | |
c00fdd17 A |
78 | static void (*hostInterfaceDeinitialize_fptr)(void); /* may not need? */ |
79 | ||
80 | #endif /* TARGET_OS_BRIDGE */ | |
1815bff5 A |
81 | |
82 | int main(int argc, char **argv) | |
83 | { | |
84 | long cnt; | |
85 | char *str, errorMessage[256]; | |
86 | kern_return_t result; | |
87 | mach_port_t masterPort; | |
cf37c299 A |
88 | int argcount = 0; |
89 | ||
1815bff5 A |
90 | // Get the name of the command. |
91 | gToolName = strrchr(argv[0], '/'); | |
92 | if (gToolName != 0) gToolName++; | |
93 | else gToolName = argv[0]; | |
cf37c299 | 94 | |
1815bff5 A |
95 | result = IOMasterPort(bootstrap_port, &masterPort); |
96 | if (result != KERN_SUCCESS) { | |
ef8ad44b A |
97 | errx(1, "Error getting the IOMaster port: %s", |
98 | mach_error_string(result)); | |
1815bff5 | 99 | } |
cf37c299 | 100 | |
1815bff5 A |
101 | gOptionsRef = IORegistryEntryFromPath(masterPort, "IODeviceTree:/options"); |
102 | if (gOptionsRef == 0) { | |
ef8ad44b | 103 | errx(1, "nvram is not supported on this system"); |
1815bff5 | 104 | } |
cf37c299 | 105 | |
1815bff5 A |
106 | for (cnt = 1; cnt < argc; cnt++) { |
107 | str = argv[cnt]; | |
108 | if (str[0] == '-' && str[1] != 0) { | |
109 | // Parse the options. | |
110 | for (str += 1 ; *str; str++) { | |
111 | switch (*str) { | |
112 | case 'p' : | |
c00fdd17 A |
113 | #if TARGET_OS_BRIDGE |
114 | if (gBridgeToIntel) { | |
115 | fprintf(stderr, "-p not supported for Mac NVRAM store.\n"); | |
116 | return 1; | |
117 | } | |
118 | #endif | |
1815bff5 A |
119 | PrintOFVariables(); |
120 | break; | |
34d340d7 A |
121 | |
122 | case 'x' : | |
123 | gUseXML = true; | |
124 | break; | |
125 | ||
1815bff5 | 126 | case 'f': |
c00fdd17 A |
127 | #if TARGET_OS_BRIDGE |
128 | if (gBridgeToIntel) { | |
129 | fprintf(stderr, "-f not supported for Mac NVRAM store.\n"); | |
130 | return 1; | |
131 | } | |
132 | #endif | |
1815bff5 A |
133 | cnt++; |
134 | if (cnt < argc && *argv[cnt] != '-') { | |
135 | ParseFile(argv[cnt]); | |
136 | } else { | |
137 | UsageMessage("missing filename"); | |
138 | } | |
139 | break; | |
cf37c299 | 140 | |
919ea02d A |
141 | case 'd': |
142 | cnt++; | |
143 | if (cnt < argc && *argv[cnt] != '-') { | |
c00fdd17 | 144 | #if TARGET_OS_BRIDGE |
919ea02d A |
145 | if (gBridgeToIntel) { |
146 | if ((result = DeleteMacOFVariable(argv[cnt])) != KERN_SUCCESS) { | |
147 | errx(1, "Error deleting variable - '%s': %s (0x%08x)", argv[cnt], | |
148 | mach_error_string(result), result); | |
149 | } | |
150 | } | |
151 | else | |
c00fdd17 | 152 | #endif |
919ea02d A |
153 | { |
154 | DeleteOFVariable(argv[cnt]); | |
155 | } | |
156 | } else { | |
157 | UsageMessage("missing name"); | |
158 | } | |
159 | break; | |
cf37c299 | 160 | |
34d340d7 | 161 | case 'c': |
c00fdd17 A |
162 | #if TARGET_OS_BRIDGE |
163 | if (gBridgeToIntel) { | |
164 | fprintf(stderr, "-c not supported for Mac NVRAM store.\n"); | |
165 | return 1; | |
166 | } | |
167 | #endif | |
34d340d7 A |
168 | ClearOFVariables(); |
169 | break; | |
9726c137 A |
170 | case 's': |
171 | // -s option is unadvertised -- advises the kernel more forcibly to | |
172 | // commit the variable to nonvolatile storage | |
173 | gUseForceSync = true; | |
174 | break; | |
c00fdd17 A |
175 | #if TARGET_OS_BRIDGE |
176 | case 'm': | |
d52496fd | 177 | // used to set nvram variables on the Intel side |
c00fdd17 A |
178 | // from the ARM side (Bridge -> Mac) |
179 | fprintf(stdout, "Using Mac NVRAM store.\n"); | |
180 | ||
181 | LinkMacNVRAMSymbols(); | |
182 | gBridgeToIntel = true; | |
183 | break; | |
184 | #endif | |
185 | ||
1815bff5 A |
186 | default: |
187 | strcpy(errorMessage, "no such option as --"); | |
188 | errorMessage[strlen(errorMessage)-1] = *str; | |
189 | UsageMessage(errorMessage); | |
190 | } | |
191 | } | |
192 | } else { | |
4c00c0ae | 193 | // Other arguments will be firmware variable requests. |
cf37c299 | 194 | argcount++; |
1815bff5 A |
195 | SetOrGetOFVariable(str); |
196 | } | |
197 | } | |
cf37c299 A |
198 | |
199 | // radar:25206371 | |
200 | if (argcount == 0 && gUseForceSync == true) { | |
201 | NVRamSyncNow(""); | |
202 | } | |
203 | ||
1815bff5 | 204 | IOObjectRelease(gOptionsRef); |
cf37c299 | 205 | |
1815bff5 A |
206 | return 0; |
207 | } | |
208 | ||
1815bff5 A |
209 | // UsageMessage(message) |
210 | // | |
211 | // Print the usage information and exit. | |
212 | // | |
213 | static void UsageMessage(char *message) | |
214 | { | |
ef8ad44b | 215 | warnx("(usage: %s)", message); |
cf37c299 | 216 | |
fc6d9e4b | 217 | printf("%s [-x] [-p] [-f filename] [-d name] [-c] name[=value] ...\n", gToolName); |
34d340d7 A |
218 | printf("\t-x use XML format for printing or reading variables\n"); |
219 | printf("\t (must appear before -p or -f)\n"); | |
4c00c0ae A |
220 | printf("\t-p print all firmware variables\n"); |
221 | printf("\t-f set firmware variables from a text file\n"); | |
83f6dbe8 | 222 | printf("\t-d delete the named variable\n"); |
34d340d7 | 223 | printf("\t-c delete all variables\n"); |
d52496fd A |
224 | #if TARGET_OS_BRIDGE |
225 | printf("\t-m set nvram variables on macOS from bridgeOS\n"); | |
226 | #endif | |
1815bff5 A |
227 | printf("\tname=value set named variable\n"); |
228 | printf("\tname print variable\n"); | |
229 | printf("Note that arguments and options are executed in order.\n"); | |
cf37c299 | 230 | |
1815bff5 A |
231 | exit(1); |
232 | } | |
233 | ||
234 | ||
235 | // States for ParseFile. | |
236 | enum { | |
237 | kFirstColumn = 0, | |
238 | kScanComment, | |
239 | kFindName, | |
240 | kCollectName, | |
241 | kFindValue, | |
242 | kCollectValue, | |
243 | kContinueValue, | |
244 | kSetenv, | |
cf37c299 | 245 | |
1815bff5 A |
246 | kMaxStringSize = 0x800, |
247 | kMaxNameSize = 0x100 | |
248 | }; | |
249 | ||
250 | ||
251 | // ParseFile(fileName) | |
252 | // | |
253 | // Open and parse the specified file. | |
254 | // | |
255 | static void ParseFile(char *fileName) | |
256 | { | |
cf37c299 A |
257 | long state, ni = 0, vi = 0; |
258 | int tc; | |
1815bff5 A |
259 | char name[kMaxNameSize]; |
260 | char value[kMaxStringSize]; | |
261 | FILE *patches; | |
ef8ad44b | 262 | kern_return_t kret; |
34d340d7 A |
263 | |
264 | if (gUseXML) { | |
265 | ParseXMLFile(fileName); | |
266 | return; | |
267 | } | |
cf37c299 | 268 | |
1815bff5 A |
269 | patches = fopen(fileName, "r"); |
270 | if (patches == 0) { | |
ef8ad44b | 271 | err(1, "Couldn't open patch file - '%s'", fileName); |
1815bff5 | 272 | } |
cf37c299 | 273 | |
1815bff5 A |
274 | state = kFirstColumn; |
275 | while ((tc = getc(patches)) != EOF) { | |
cf37c299 | 276 | if(ni==(kMaxNameSize-1)) |
ef8ad44b | 277 | errx(1, "Name exceeded max length of %d", kMaxNameSize); |
34d340d7 | 278 | if(vi==(kMaxStringSize-1)) |
ef8ad44b | 279 | errx(1, "Value exceeded max length of %d", kMaxStringSize); |
1815bff5 A |
280 | switch (state) { |
281 | case kFirstColumn : | |
282 | ni = 0; | |
283 | vi = 0; | |
284 | if (tc == '#') { | |
285 | state = kScanComment; | |
286 | } else if (tc == '\n') { | |
287 | // state stays kFirstColumn. | |
288 | } else if (isspace(tc)) { | |
289 | state = kFindName; | |
290 | } else { | |
291 | state = kCollectName; | |
292 | name[ni++] = tc; | |
293 | } | |
294 | break; | |
cf37c299 | 295 | |
1815bff5 A |
296 | case kScanComment : |
297 | if (tc == '\n') { | |
298 | state = kFirstColumn; | |
299 | } else { | |
300 | // state stays kScanComment. | |
301 | } | |
302 | break; | |
cf37c299 | 303 | |
1815bff5 A |
304 | case kFindName : |
305 | if (tc == '\n') { | |
306 | state = kFirstColumn; | |
307 | } else if (isspace(tc)) { | |
308 | // state stays kFindName. | |
309 | } else { | |
310 | state = kCollectName; | |
311 | name[ni++] = tc; | |
312 | } | |
313 | break; | |
cf37c299 | 314 | |
1815bff5 A |
315 | case kCollectName : |
316 | if (tc == '\n') { | |
317 | name[ni] = 0; | |
ef8ad44b | 318 | warnx("Name must be followed by white space - '%s'", name); |
1815bff5 A |
319 | state = kFirstColumn; |
320 | } else if (isspace(tc)) { | |
321 | state = kFindValue; | |
322 | } else { | |
323 | name[ni++] = tc; | |
324 | // state staus kCollectName. | |
325 | } | |
326 | break; | |
cf37c299 | 327 | |
1815bff5 A |
328 | case kFindValue : |
329 | case kContinueValue : | |
330 | if (tc == '\n') { | |
331 | state = kSetenv; | |
332 | } else if (isspace(tc)) { | |
333 | // state stays kFindValue or kContinueValue. | |
334 | } else { | |
335 | state = kCollectValue; | |
336 | value[vi++] = tc; | |
337 | } | |
338 | break; | |
cf37c299 | 339 | |
1815bff5 A |
340 | case kCollectValue : |
341 | if (tc == '\n') { | |
342 | if (value[vi-1] == '\\') { | |
343 | value[vi-1] = '\r'; | |
344 | state = kContinueValue; | |
345 | } else { | |
346 | state = kSetenv; | |
347 | } | |
348 | } else { | |
349 | // state stays kCollectValue. | |
350 | value[vi++] = tc; | |
351 | } | |
352 | break; | |
353 | } | |
cf37c299 | 354 | |
1815bff5 A |
355 | if (state == kSetenv) { |
356 | name[ni] = 0; | |
357 | value[vi] = 0; | |
ef8ad44b A |
358 | if ((kret = SetOFVariable(name, value)) != KERN_SUCCESS) { |
359 | errx(1, "Error setting variable - '%s': %s", name, | |
360 | mach_error_string(kret)); | |
1815bff5 A |
361 | } |
362 | state = kFirstColumn; | |
363 | } | |
364 | } | |
cf37c299 | 365 | |
1815bff5 | 366 | if (state != kFirstColumn) { |
ef8ad44b | 367 | errx(1, "Last line ended abruptly"); |
1815bff5 A |
368 | } |
369 | } | |
370 | ||
34d340d7 A |
371 | // ParseXMLFile(fileName) |
372 | // | |
373 | // Open and parse the specified file in XML format, | |
374 | // and set variables appropriately. | |
375 | // | |
376 | static void ParseXMLFile(char *fileName) | |
377 | { | |
378 | CFPropertyListRef plist; | |
cf37c299 A |
379 | int fd; |
380 | struct stat sb; | |
381 | char *buffer; | |
382 | CFReadStreamRef stream; | |
383 | CFPropertyListFormat format = kCFPropertyListBinaryFormat_v1_0; | |
384 | ||
385 | fd = open(fileName, O_RDONLY | O_NOFOLLOW, S_IFREG); | |
386 | if (fd == -1) { | |
387 | errx(1, "Could not open %s: %s", fileName, strerror(errno)); | |
34d340d7 A |
388 | } |
389 | ||
cf37c299 A |
390 | if (fstat(fd, &sb) == -1) { |
391 | errx(1, "Could not fstat %s: %s", fileName, strerror(errno)); | |
34d340d7 A |
392 | } |
393 | ||
cf37c299 A |
394 | if (sb.st_size > UINT32_MAX) { |
395 | errx(1, "too big for our purposes"); | |
396 | } | |
34d340d7 | 397 | |
cf37c299 A |
398 | buffer = malloc((size_t)sb.st_size); |
399 | if (buffer == NULL) { | |
400 | errx(1, "Could not allocate buffer"); | |
34d340d7 A |
401 | } |
402 | ||
cf37c299 A |
403 | if (read(fd, buffer, (size_t)sb.st_size) != sb.st_size) { |
404 | errx(1, "Could not read %s: %s", fileName, strerror(errno)); | |
405 | } | |
34d340d7 | 406 | |
cf37c299 | 407 | close(fd); |
34d340d7 | 408 | |
cf37c299 A |
409 | stream = CFReadStreamCreateWithBytesNoCopy(kCFAllocatorDefault, |
410 | (const UInt8 *)buffer, | |
411 | (CFIndex)sb.st_size, | |
412 | kCFAllocatorNull); | |
413 | if (stream == NULL) { | |
414 | errx(1, "Could not create stream from serialized data"); | |
415 | } | |
416 | ||
417 | if (!CFReadStreamOpen(stream)) { | |
418 | errx(1, "Could not open the stream"); | |
419 | } | |
420 | ||
421 | plist = CFPropertyListCreateWithStream(kCFAllocatorDefault, | |
422 | stream, | |
423 | (CFIndex)sb.st_size, | |
424 | kCFPropertyListImmutable, | |
425 | &format, | |
426 | NULL); | |
34d340d7 A |
427 | |
428 | if (plist == NULL) { | |
ef8ad44b | 429 | errx(1, "Error parsing XML file"); |
34d340d7 A |
430 | } |
431 | ||
cf37c299 A |
432 | CFReadStreamClose(stream); |
433 | ||
434 | CFRelease(stream); | |
435 | ||
436 | free(buffer); | |
34d340d7 A |
437 | |
438 | CFDictionaryApplyFunction(plist, &SetOFVariableFromFile, 0); | |
439 | ||
440 | CFRelease(plist); | |
441 | } | |
442 | ||
1815bff5 A |
443 | // SetOrGetOFVariable(str) |
444 | // | |
2fc1e207 | 445 | // Parse the input string, then set or get the specified |
4c00c0ae | 446 | // firmware variable. |
1815bff5 A |
447 | // |
448 | static void SetOrGetOFVariable(char *str) | |
449 | { | |
450 | long set = 0; | |
451 | char *name; | |
452 | char *value; | |
453 | CFStringRef nameRef; | |
454 | CFTypeRef valueRef; | |
455 | kern_return_t result; | |
cf37c299 | 456 | |
1815bff5 A |
457 | // OF variable name is first. |
458 | name = str; | |
cf37c299 | 459 | |
1815bff5 A |
460 | // Find the equal sign for set |
461 | while (*str) { | |
462 | if (*str == '=') { | |
463 | set = 1; | |
464 | *str++ = '\0'; | |
465 | break; | |
466 | } | |
467 | str++; | |
468 | } | |
cf37c299 | 469 | |
1815bff5 A |
470 | if (set == 1) { |
471 | // On sets, the OF variable's value follows the equal sign. | |
472 | value = str; | |
c00fdd17 A |
473 | #if TARGET_OS_BRIDGE |
474 | if (gBridgeToIntel) { | |
475 | result = SetMacOFVariable(name, value); | |
476 | } | |
477 | else | |
478 | #endif | |
479 | { | |
480 | result = SetOFVariable(name, value); | |
481 | NVRamSyncNow(name); /* Try syncing the new data to device, best effort! */ | |
482 | } | |
1815bff5 | 483 | if (result != KERN_SUCCESS) { |
ef8ad44b A |
484 | errx(1, "Error setting variable - '%s': %s", name, |
485 | mach_error_string(result)); | |
1815bff5 A |
486 | } |
487 | } else { | |
c00fdd17 A |
488 | #if TARGET_OS_BRIDGE |
489 | if (gBridgeToIntel) { | |
490 | result = GetMacOFVariable(name, &value); | |
491 | if (result != KERN_SUCCESS) { | |
492 | errx(1, "Error getting variable - '%s': %s", name, | |
493 | mach_error_string(result)); | |
494 | } | |
495 | nameRef = CFStringCreateWithCString(kCFAllocatorDefault, name, kCFStringEncodingUTF8); | |
496 | valueRef = CFStringCreateWithCString(kCFAllocatorDefault, value, kCFStringEncodingUTF8); | |
919ea02d | 497 | free(value); |
c00fdd17 A |
498 | } |
499 | else | |
500 | #endif | |
501 | { | |
502 | result = GetOFVariable(name, &nameRef, &valueRef); | |
503 | if (result != KERN_SUCCESS) { | |
504 | errx(1, "Error getting variable - '%s': %s", name, | |
505 | mach_error_string(result)); | |
506 | } | |
1815bff5 | 507 | } |
cf37c299 | 508 | |
1815bff5 A |
509 | PrintOFVariable(nameRef, valueRef, 0); |
510 | CFRelease(nameRef); | |
511 | CFRelease(valueRef); | |
512 | } | |
513 | } | |
514 | ||
c00fdd17 A |
515 | #if TARGET_OS_BRIDGE |
516 | static kern_return_t LinkMacNVRAMSymbols() | |
517 | { | |
518 | gDL_handle = dlopen("libMacEFIHostInterface.dylib", RTLD_LAZY); | |
519 | if (gDL_handle == NULL) { | |
520 | errx(errno, "Failed to dlopen libMacEFIHostInterface.dylib"); | |
521 | return KERN_FAILURE; /* NOTREACHED */ | |
522 | } | |
523 | ||
524 | hostInterfaceInitialize_fptr = dlsym(gDL_handle, "hostInterfaceInitialize"); | |
525 | if (hostInterfaceInitialize_fptr == NULL) { | |
526 | errx(errno, "failed to link hostInterfaceInitialize"); | |
527 | } | |
528 | createNvramHostInterface_fptr = dlsym(gDL_handle, "createNvramHostInterface"); | |
529 | if (createNvramHostInterface_fptr == NULL) { | |
530 | errx(errno, "failed to link createNvramHostInterface"); | |
531 | } | |
532 | destroyNvramHostInterface_fptr = dlsym(gDL_handle, "destroyNvramHostInterface"); | |
533 | if (destroyNvramHostInterface_fptr == NULL) { | |
534 | errx(errno, "failed to link destroyNvramHostInterface"); | |
535 | } | |
536 | getNVRAMVariable_fptr = dlsym(gDL_handle, "getNVRAMVariable"); | |
537 | if (getNVRAMVariable_fptr == NULL) { | |
538 | errx(errno, "failed to link getNVRAMVariable"); | |
539 | } | |
540 | setNVRAMVariable_fptr = dlsym(gDL_handle, "setNVRAMVariable"); | |
541 | if (setNVRAMVariable_fptr == NULL) { | |
542 | errx(errno, "failed to link setNVRAMVariable"); | |
543 | } | |
919ea02d A |
544 | deleteNVRAMVariable_fptr = dlsym(gDL_handle, "deleteNVRAMVariable"); |
545 | if (deleteNVRAMVariable_fptr == NULL) { | |
546 | errx(errno, "failed to link deleteNVRAMVariable"); | |
547 | } | |
c00fdd17 A |
548 | hostInterfaceDeinitialize_fptr = dlsym(gDL_handle, "hostInterfaceDeinitialize"); |
549 | if (hostInterfaceDeinitialize_fptr == NULL) { | |
550 | errx(errno, "failed to link hostInterfaceDeinitialize"); | |
551 | } | |
552 | ||
553 | /* also do the initialization */ | |
554 | hostInterfaceInitialize_fptr(); | |
555 | gNvramInterface = createNvramHostInterface_fptr(NULL); | |
556 | ||
557 | return KERN_SUCCESS; | |
558 | } | |
559 | #endif | |
1815bff5 A |
560 | |
561 | // GetOFVariable(name, nameRef, valueRef) | |
562 | // | |
4c00c0ae | 563 | // Get the named firmware variable. |
1815bff5 A |
564 | // Return it and it's symbol in valueRef and nameRef. |
565 | // | |
566 | static kern_return_t GetOFVariable(char *name, CFStringRef *nameRef, | |
567 | CFTypeRef *valueRef) | |
568 | { | |
569 | *nameRef = CFStringCreateWithCString(kCFAllocatorDefault, name, | |
2fc1e207 | 570 | kCFStringEncodingUTF8); |
1815bff5 | 571 | if (*nameRef == 0) { |
ef8ad44b | 572 | errx(1, "Error creating CFString for key %s", name); |
1815bff5 | 573 | } |
cf37c299 | 574 | |
1815bff5 | 575 | *valueRef = IORegistryEntryCreateCFProperty(gOptionsRef, *nameRef, 0, 0); |
ef8ad44b | 576 | if (*valueRef == 0) return kIOReturnNotFound; |
cf37c299 | 577 | |
1815bff5 A |
578 | return KERN_SUCCESS; |
579 | } | |
580 | ||
c00fdd17 A |
581 | #if TARGET_OS_BRIDGE |
582 | // GetMacOFVariable(name, value) | |
583 | // | |
584 | // Get the named firmware variable from the Intel side. | |
585 | // Return the value in value | |
586 | // | |
587 | static kern_return_t GetMacOFVariable(char *name, char **value) | |
588 | { | |
589 | uint32_t value_size; | |
c00fdd17 | 590 | |
919ea02d | 591 | return getNVRAMVariable_fptr(gNvramInterface, name, value, &value_size); |
c00fdd17 A |
592 | } |
593 | #endif | |
1815bff5 A |
594 | |
595 | // SetOFVariable(name, value) | |
596 | // | |
4c00c0ae | 597 | // Set or create an firmware variable with name and value. |
1815bff5 A |
598 | // |
599 | static kern_return_t SetOFVariable(char *name, char *value) | |
600 | { | |
601 | CFStringRef nameRef; | |
602 | CFTypeRef valueRef; | |
603 | CFTypeID typeID; | |
ef8ad44b | 604 | kern_return_t result = KERN_SUCCESS; |
cf37c299 | 605 | |
919ea02d A |
606 | nameRef = CFStringCreateWithCString(kCFAllocatorDefault, name, |
607 | kCFStringEncodingUTF8); | |
608 | if (nameRef == 0) { | |
609 | errx(1, "Error creating CFString for key %s", name); | |
610 | } | |
cf37c299 | 611 | |
919ea02d A |
612 | valueRef = IORegistryEntryCreateCFProperty(gOptionsRef, nameRef, 0, 0); |
613 | if (valueRef) { | |
614 | typeID = CFGetTypeID(valueRef); | |
615 | CFRelease(valueRef); | |
cf37c299 | 616 | |
919ea02d A |
617 | valueRef = ConvertValueToCFTypeRef(typeID, value); |
618 | if (valueRef == 0) { | |
619 | errx(1, "Error creating CFTypeRef for value %s", value); | |
620 | } result = IORegistryEntrySetCFProperty(gOptionsRef, nameRef, valueRef); | |
621 | } else { | |
622 | while (1) { | |
623 | // In the default case, try data, string, number, then boolean. | |
624 | ||
625 | valueRef = ConvertValueToCFTypeRef(CFDataGetTypeID(), value); | |
626 | if (valueRef != 0) { | |
627 | result = IORegistryEntrySetCFProperty(gOptionsRef, nameRef, valueRef); | |
628 | if (result == KERN_SUCCESS) break; | |
629 | } | |
630 | ||
631 | valueRef = ConvertValueToCFTypeRef(CFStringGetTypeID(), value); | |
632 | if (valueRef != 0) { | |
633 | result = IORegistryEntrySetCFProperty(gOptionsRef, nameRef, valueRef); | |
634 | if (result == KERN_SUCCESS) break; | |
635 | } | |
636 | ||
637 | valueRef = ConvertValueToCFTypeRef(CFNumberGetTypeID(), value); | |
638 | if (valueRef != 0) { | |
639 | result = IORegistryEntrySetCFProperty(gOptionsRef, nameRef, valueRef); | |
640 | if (result == KERN_SUCCESS) break; | |
641 | } | |
642 | ||
643 | valueRef = ConvertValueToCFTypeRef(CFBooleanGetTypeID(), value); | |
644 | if (valueRef != 0) { | |
645 | result = IORegistryEntrySetCFProperty(gOptionsRef, nameRef, valueRef); | |
646 | if (result == KERN_SUCCESS) break; | |
647 | } | |
648 | ||
649 | break; | |
650 | } | |
20e66415 | 651 | } |
cf37c299 | 652 | |
1815bff5 | 653 | CFRelease(nameRef); |
cf37c299 | 654 | |
1815bff5 A |
655 | return result; |
656 | } | |
657 | ||
c00fdd17 A |
658 | #if TARGET_OS_BRIDGE |
659 | static kern_return_t SetMacOFVariable(char *name, char *value) | |
660 | { | |
919ea02d | 661 | return setNVRAMVariable_fptr(gNvramInterface, name, value); |
c00fdd17 A |
662 | } |
663 | #endif | |
1815bff5 | 664 | |
83f6dbe8 A |
665 | // DeleteOFVariable(name) |
666 | // | |
4c00c0ae | 667 | // Delete the named firmware variable. |
cf37c299 | 668 | // |
83f6dbe8 A |
669 | // |
670 | static void DeleteOFVariable(char *name) | |
671 | { | |
672 | SetOFVariable(kIONVRAMDeletePropertyKey, name); | |
673 | } | |
674 | ||
c00fdd17 | 675 | #if TARGET_OS_BRIDGE |
919ea02d | 676 | static kern_return_t DeleteMacOFVariable(char *name) |
c00fdd17 | 677 | { |
919ea02d | 678 | return deleteNVRAMVariable_fptr(gNvramInterface, name); |
c00fdd17 A |
679 | } |
680 | #endif | |
681 | ||
8459d725 A |
682 | static void NVRamSyncNow(char *name) |
683 | { | |
9726c137 A |
684 | if (!gUseForceSync) { |
685 | SetOFVariable(kIONVRAMSyncNowPropertyKey, name); | |
686 | } else { | |
687 | SetOFVariable(kIONVRAMForceSyncNowPropertyKey, name); | |
688 | } | |
8459d725 | 689 | } |
83f6dbe8 | 690 | |
1815bff5 A |
691 | // PrintOFVariables() |
692 | // | |
4c00c0ae | 693 | // Print all of the firmware variables. |
1815bff5 | 694 | // |
cf37c299 | 695 | static void PrintOFVariables(void) |
1815bff5 A |
696 | { |
697 | kern_return_t result; | |
698 | CFMutableDictionaryRef dict; | |
cf37c299 | 699 | |
1815bff5 A |
700 | result = IORegistryEntryCreateCFProperties(gOptionsRef, &dict, 0, 0); |
701 | if (result != KERN_SUCCESS) { | |
ef8ad44b | 702 | errx(1, "Error getting the firmware variables: %s", mach_error_string(result)); |
1815bff5 | 703 | } |
34d340d7 A |
704 | |
705 | if (gUseXML) { | |
706 | CFDataRef data; | |
707 | ||
cf37c299 | 708 | data = CFPropertyListCreateData( kCFAllocatorDefault, dict, kCFPropertyListXMLFormat_v1_0, 0, NULL ); |
34d340d7 | 709 | if (data == NULL) { |
ef8ad44b | 710 | errx(1, "Error converting variables to xml"); |
34d340d7 A |
711 | } |
712 | ||
713 | fwrite(CFDataGetBytePtr(data), sizeof(UInt8), CFDataGetLength(data), stdout); | |
714 | ||
715 | CFRelease(data); | |
716 | ||
717 | } else { | |
718 | ||
719 | CFDictionaryApplyFunction(dict, &PrintOFVariable, 0); | |
720 | ||
721 | } | |
cf37c299 | 722 | |
1815bff5 A |
723 | CFRelease(dict); |
724 | } | |
725 | ||
1815bff5 A |
726 | // PrintOFVariable(key, value, context) |
727 | // | |
4c00c0ae | 728 | // Print the given firmware variable. |
1815bff5 A |
729 | // |
730 | static void PrintOFVariable(const void *key, const void *value, void *context) | |
731 | { | |
732 | long cnt, cnt2; | |
2fc1e207 A |
733 | CFIndex nameLen; |
734 | char *nameBuffer = 0; | |
1815bff5 A |
735 | const char *nameString; |
736 | char numberBuffer[10]; | |
b51d5b5f A |
737 | const uint8_t *dataPtr; |
738 | uint8_t dataChar; | |
1815bff5 | 739 | char *dataBuffer = 0; |
2fc1e207 A |
740 | CFIndex valueLen; |
741 | char *valueBuffer = 0; | |
b51d5b5f | 742 | const char *valueString = 0; |
cf37c299 A |
743 | uint32_t number; |
744 | long length; | |
1815bff5 | 745 | CFTypeID typeID; |
cf37c299 | 746 | |
887d5eed A |
747 | if (gUseXML) { |
748 | CFDataRef data; | |
749 | CFDictionaryRef dict = CFDictionaryCreate(kCFAllocatorDefault, &key, &value, 1, | |
750 | &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); | |
751 | if (dict == NULL) { | |
752 | errx(1, "Error creating dictionary for variable value"); | |
753 | } | |
754 | ||
755 | data = CFPropertyListCreateData( kCFAllocatorDefault, dict, kCFPropertyListXMLFormat_v1_0, 0, NULL ); | |
756 | if (data == NULL) { | |
757 | errx(1, "Error creating xml plist for variable"); | |
758 | } | |
759 | ||
760 | fwrite(CFDataGetBytePtr(data), sizeof(UInt8), CFDataGetLength(data), stdout); | |
761 | ||
762 | CFRelease(dict); | |
763 | CFRelease(data); | |
764 | return; | |
765 | } | |
766 | ||
1815bff5 | 767 | // Get the OF variable's name. |
d52496fd A |
768 | nameLen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(key), |
769 | kCFStringEncodingUTF8) + 1; | |
2fc1e207 A |
770 | nameBuffer = malloc(nameLen); |
771 | if( nameBuffer && CFStringGetCString(key, nameBuffer, nameLen, kCFStringEncodingUTF8) ) | |
772 | nameString = nameBuffer; | |
773 | else { | |
ef8ad44b | 774 | warnx("Unable to convert property name to C string"); |
2fc1e207 A |
775 | nameString = "<UNPRINTABLE>"; |
776 | } | |
cf37c299 | 777 | |
1815bff5 A |
778 | // Get the OF variable's type. |
779 | typeID = CFGetTypeID(value); | |
cf37c299 | 780 | |
2fc1e207 | 781 | if (typeID == CFBooleanGetTypeID()) { |
1815bff5 A |
782 | if (CFBooleanGetValue(value)) valueString = "true"; |
783 | else valueString = "false"; | |
784 | } else if (typeID == CFNumberGetTypeID()) { | |
785 | CFNumberGetValue(value, kCFNumberSInt32Type, &number); | |
786 | if (number == 0xFFFFFFFF) sprintf(numberBuffer, "-1"); | |
787 | else if (number < 1000) sprintf(numberBuffer, "%d", number); | |
788 | else sprintf(numberBuffer, "0x%x", number); | |
789 | valueString = numberBuffer; | |
790 | } else if (typeID == CFStringGetTypeID()) { | |
d52496fd A |
791 | valueLen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(value), |
792 | kCFStringEncodingUTF8) + 1; | |
2fc1e207 A |
793 | valueBuffer = malloc(valueLen + 1); |
794 | if ( valueBuffer && CFStringGetCString(value, valueBuffer, valueLen, kCFStringEncodingUTF8) ) | |
795 | valueString = valueBuffer; | |
796 | else { | |
ef8ad44b | 797 | warnx("Unable to convert value to C string"); |
2fc1e207 A |
798 | valueString = "<UNPRINTABLE>"; |
799 | } | |
1815bff5 A |
800 | } else if (typeID == CFDataGetTypeID()) { |
801 | length = CFDataGetLength(value); | |
802 | if (length == 0) valueString = ""; | |
803 | else { | |
804 | dataBuffer = malloc(length * 3 + 1); | |
805 | if (dataBuffer != 0) { | |
806 | dataPtr = CFDataGetBytePtr(value); | |
807 | for (cnt = cnt2 = 0; cnt < length; cnt++) { | |
808 | dataChar = dataPtr[cnt]; | |
1a7e3f61 A |
809 | if (isprint(dataChar) && dataChar != '%') { |
810 | dataBuffer[cnt2++] = dataChar; | |
811 | } else { | |
1815bff5 A |
812 | sprintf(dataBuffer + cnt2, "%%%02x", dataChar); |
813 | cnt2 += 3; | |
814 | } | |
815 | } | |
816 | dataBuffer[cnt2] = '\0'; | |
817 | valueString = dataBuffer; | |
818 | } | |
819 | } | |
2fc1e207 A |
820 | } else { |
821 | valueString="<INVALID>"; | |
822 | } | |
cf37c299 | 823 | |
1815bff5 A |
824 | if ((nameString != 0) && (valueString != 0)) |
825 | printf("%s\t%s\n", nameString, valueString); | |
cf37c299 | 826 | |
1815bff5 | 827 | if (dataBuffer != 0) free(dataBuffer); |
2fc1e207 A |
828 | if (nameBuffer != 0) free(nameBuffer); |
829 | if (valueBuffer != 0) free(valueBuffer); | |
1815bff5 A |
830 | } |
831 | ||
34d340d7 A |
832 | // ClearOFVariables() |
833 | // | |
834 | // Deletes all OF variables | |
835 | // | |
836 | static void ClearOFVariables(void) | |
837 | { | |
838 | kern_return_t result; | |
839 | CFMutableDictionaryRef dict; | |
840 | ||
841 | result = IORegistryEntryCreateCFProperties(gOptionsRef, &dict, 0, 0); | |
842 | if (result != KERN_SUCCESS) { | |
ef8ad44b | 843 | errx(1, "Error getting the firmware variables: %s", mach_error_string(result)); |
34d340d7 A |
844 | } |
845 | CFDictionaryApplyFunction(dict, &ClearOFVariable, 0); | |
846 | ||
847 | CFRelease(dict); | |
848 | } | |
849 | ||
850 | static void ClearOFVariable(const void *key, const void *value, void *context) | |
851 | { | |
852 | kern_return_t result; | |
853 | result = IORegistryEntrySetCFProperty(gOptionsRef, | |
854 | CFSTR(kIONVRAMDeletePropertyKey), key); | |
855 | if (result != KERN_SUCCESS) { | |
ef8ad44b | 856 | errx(1, "Error clearing firmware variables: %s", mach_error_string(result)); |
34d340d7 A |
857 | } |
858 | } | |
1815bff5 A |
859 | |
860 | // ConvertValueToCFTypeRef(typeID, value) | |
861 | // | |
862 | // Convert the value into a CFType given the typeID. | |
863 | // | |
864 | static CFTypeRef ConvertValueToCFTypeRef(CFTypeID typeID, char *value) | |
865 | { | |
919ea02d A |
866 | CFTypeRef valueRef = 0; |
867 | long cnt, cnt2, length; | |
868 | unsigned long number, tmp; | |
869 | ||
870 | if (typeID == CFBooleanGetTypeID()) { | |
871 | if (!strcmp("true", value)) valueRef = kCFBooleanTrue; | |
872 | else if (!strcmp("false", value)) valueRef = kCFBooleanFalse; | |
873 | } else if (typeID == CFNumberGetTypeID()) { | |
874 | number = strtol(value, 0, 0); | |
875 | valueRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, | |
876 | &number); | |
877 | } else if (typeID == CFStringGetTypeID()) { | |
878 | valueRef = CFStringCreateWithCString(kCFAllocatorDefault, value, | |
879 | kCFStringEncodingUTF8); | |
880 | } else if (typeID == CFDataGetTypeID()) { | |
881 | length = strlen(value); | |
882 | for (cnt = cnt2 = 0; cnt < length; cnt++, cnt2++) { | |
883 | if (value[cnt] == '%') { | |
884 | if (!ishexnumber(value[cnt + 1]) || | |
885 | !ishexnumber(value[cnt + 2])) return 0; | |
886 | number = toupper(value[++cnt]) - '0'; | |
887 | if (number > 9) number -= 7; | |
888 | tmp = toupper(value[++cnt]) - '0'; | |
889 | if (tmp > 9) tmp -= 7; | |
890 | number = (number << 4) + tmp; | |
891 | value[cnt2] = number; | |
892 | } else value[cnt2] = value[cnt]; | |
893 | } | |
894 | valueRef = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (const UInt8 *)value, | |
895 | cnt2, kCFAllocatorDefault); | |
896 | } else return 0; | |
cf37c299 | 897 | |
919ea02d | 898 | return valueRef; |
1815bff5 | 899 | } |
09fd88e4 | 900 | |
34d340d7 A |
901 | static void SetOFVariableFromFile(const void *key, const void *value, void *context) |
902 | { | |
903 | kern_return_t result; | |
904 | ||
905 | result = IORegistryEntrySetCFProperty(gOptionsRef, key, value); | |
906 | if ( result != KERN_SUCCESS ) { | |
cf37c299 | 907 | long nameLen; |
34d340d7 A |
908 | char *nameBuffer; |
909 | char *nameString; | |
910 | ||
911 | // Get the variable's name. | |
d52496fd A |
912 | nameLen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(key), |
913 | kCFStringEncodingUTF8) + 1; | |
34d340d7 A |
914 | nameBuffer = malloc(nameLen); |
915 | if( nameBuffer && CFStringGetCString(key, nameBuffer, nameLen, kCFStringEncodingUTF8) ) | |
916 | nameString = nameBuffer; | |
917 | else { | |
ef8ad44b | 918 | warnx("Unable to convert property name to C string"); |
34d340d7 A |
919 | nameString = "<UNPRINTABLE>"; |
920 | } | |
ef8ad44b A |
921 | errx(1, "Error setting variable - '%s': %s", nameString, |
922 | mach_error_string(result)); | |
34d340d7 A |
923 | } |
924 | } |