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