/*
- * Copyright (c) 2000-2012 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2016 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
#include <stdio.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/IOKitKeys.h>
+#include <IOKit/IOKitKeysPrivate.h>
#include <CoreFoundation/CoreFoundation.h>
#include <err.h>
#include <mach/mach_error.h>
+#include <sys/stat.h>
// Prototypes
static void UsageMessage(char *message);
static char *gToolName;
static io_registry_entry_t gOptionsRef;
static bool gUseXML;
+static bool gUseForceSync;
+#if TARGET_OS_BRIDGE /* Stuff for nvram bridge -> intel */
+#include <dlfcn.h>
+#include <libMacEFIManager/MacEFIHostInterfaceAPI.h>
+
+static kern_return_t LinkMacNVRAMSymbols(void);
+static kern_return_t GetMacOFVariable(char *name, char **value);
+static kern_return_t SetMacOFVariable(char *name, char *value);
+static void DeleteMacOFVariable(char *name);
+
+static bool gBridgeToIntel;
+static void *gDL_handle;
+static void *gNvramInterface;
+
+static void (*hostInterfaceInitialize_fptr)(void);
+static void *(*createNvramHostInterface_fptr)(const char *handle);
+static kern_return_t (*destroyNvramHostInterface_fptr)(void *interface);
+static kern_return_t (*getNVRAMVariable_fptr)(void *interface, char *name, char **buffer, uint32_t *size);
+static kern_return_t (*setNVRAMVariable_fptr)(void *interface, char *name, char *buffer, uint32_t size);
+static void (*hostInterfaceDeinitialize_fptr)(void); /* may not need? */
+
+#endif /* TARGET_OS_BRIDGE */
int main(int argc, char **argv)
{
char *str, errorMessage[256];
kern_return_t result;
mach_port_t masterPort;
-
+ int argcount = 0;
+
// Get the name of the command.
gToolName = strrchr(argv[0], '/');
if (gToolName != 0) gToolName++;
else gToolName = argv[0];
-
+
result = IOMasterPort(bootstrap_port, &masterPort);
if (result != KERN_SUCCESS) {
errx(1, "Error getting the IOMaster port: %s",
mach_error_string(result));
}
-
+
gOptionsRef = IORegistryEntryFromPath(masterPort, "IODeviceTree:/options");
if (gOptionsRef == 0) {
errx(1, "nvram is not supported on this system");
}
-
+
for (cnt = 1; cnt < argc; cnt++) {
str = argv[cnt];
if (str[0] == '-' && str[1] != 0) {
for (str += 1 ; *str; str++) {
switch (*str) {
case 'p' :
+#if TARGET_OS_BRIDGE
+ if (gBridgeToIntel) {
+ fprintf(stderr, "-p not supported for Mac NVRAM store.\n");
+ return 1;
+ }
+#endif
PrintOFVariables();
break;
break;
case 'f':
+#if TARGET_OS_BRIDGE
+ if (gBridgeToIntel) {
+ fprintf(stderr, "-f not supported for Mac NVRAM store.\n");
+ return 1;
+ }
+#endif
cnt++;
if (cnt < argc && *argv[cnt] != '-') {
ParseFile(argv[cnt]);
UsageMessage("missing filename");
}
break;
-
+
case 'd':
+#if TARGET_OS_BRIDGE
+ if (gBridgeToIntel) {
+ fprintf(stderr, "-d not supported for Mac NVRAM store.\n");
+ return 1;
+ }
+#endif
cnt++;
if (cnt < argc && *argv[cnt] != '-') {
DeleteOFVariable(argv[cnt]);
UsageMessage("missing name");
}
break;
-
+
case 'c':
+#if TARGET_OS_BRIDGE
+ if (gBridgeToIntel) {
+ fprintf(stderr, "-c not supported for Mac NVRAM store.\n");
+ return 1;
+ }
+#endif
ClearOFVariables();
break;
-
+ case 's':
+ // -s option is unadvertised -- advises the kernel more forcibly to
+ // commit the variable to nonvolatile storage
+ gUseForceSync = true;
+ break;
+#if TARGET_OS_BRIDGE
+ case 'm':
+ // -m option is unadvertised -- used to set nvram variables on the Intel side
+ // from the ARM side (Bridge -> Mac)
+ fprintf(stdout, "Using Mac NVRAM store.\n");
+
+ LinkMacNVRAMSymbols();
+ gBridgeToIntel = true;
+ break;
+#endif
+
default:
strcpy(errorMessage, "no such option as --");
errorMessage[strlen(errorMessage)-1] = *str;
}
} else {
// Other arguments will be firmware variable requests.
+ argcount++;
SetOrGetOFVariable(str);
}
}
-
+
+ // radar:25206371
+ if (argcount == 0 && gUseForceSync == true) {
+ NVRamSyncNow("");
+ }
+
IOObjectRelease(gOptionsRef);
-
+
return 0;
}
static void UsageMessage(char *message)
{
warnx("(usage: %s)", message);
-
+
printf("%s [-x] [-p] [-f filename] [-d name] [-c] name[=value] ...\n", gToolName);
printf("\t-x use XML format for printing or reading variables\n");
printf("\t (must appear before -p or -f)\n");
printf("\tname=value set named variable\n");
printf("\tname print variable\n");
printf("Note that arguments and options are executed in order.\n");
-
+
exit(1);
}
kCollectValue,
kContinueValue,
kSetenv,
-
+
kMaxStringSize = 0x800,
kMaxNameSize = 0x100
};
//
static void ParseFile(char *fileName)
{
- long state, tc, ni = 0, vi = 0;
+ long state, ni = 0, vi = 0;
+ int tc;
char name[kMaxNameSize];
char value[kMaxStringSize];
FILE *patches;
ParseXMLFile(fileName);
return;
}
-
+
patches = fopen(fileName, "r");
if (patches == 0) {
err(1, "Couldn't open patch file - '%s'", fileName);
}
-
+
state = kFirstColumn;
while ((tc = getc(patches)) != EOF) {
- if(ni==(kMaxNameSize-1))
+ if(ni==(kMaxNameSize-1))
errx(1, "Name exceeded max length of %d", kMaxNameSize);
if(vi==(kMaxStringSize-1))
errx(1, "Value exceeded max length of %d", kMaxStringSize);
name[ni++] = tc;
}
break;
-
+
case kScanComment :
if (tc == '\n') {
state = kFirstColumn;
// state stays kScanComment.
}
break;
-
+
case kFindName :
if (tc == '\n') {
state = kFirstColumn;
name[ni++] = tc;
}
break;
-
+
case kCollectName :
if (tc == '\n') {
name[ni] = 0;
// state staus kCollectName.
}
break;
-
+
case kFindValue :
case kContinueValue :
if (tc == '\n') {
value[vi++] = tc;
}
break;
-
+
case kCollectValue :
if (tc == '\n') {
if (value[vi-1] == '\\') {
}
break;
}
-
+
if (state == kSetenv) {
name[ni] = 0;
value[vi] = 0;
state = kFirstColumn;
}
}
-
+
if (state != kFirstColumn) {
errx(1, "Last line ended abruptly");
}
}
-
// ParseXMLFile(fileName)
//
// Open and parse the specified file in XML format,
static void ParseXMLFile(char *fileName)
{
CFPropertyListRef plist;
- CFURLRef fileURL = NULL;
- CFStringRef filePath = NULL;
- CFStringRef errorString = NULL;
- CFDataRef data = NULL;
- SInt32 errorCode = 0;
-
- filePath = CFStringCreateWithCString(kCFAllocatorDefault, fileName, kCFStringEncodingUTF8);
- if (filePath == NULL) {
- errx(1, "Could not create file path string");
+ int fd;
+ struct stat sb;
+ char *buffer;
+ CFReadStreamRef stream;
+ CFPropertyListFormat format = kCFPropertyListBinaryFormat_v1_0;
+
+ fd = open(fileName, O_RDONLY | O_NOFOLLOW, S_IFREG);
+ if (fd == -1) {
+ errx(1, "Could not open %s: %s", fileName, strerror(errno));
}
- // Create a URL that specifies the file we will create to
- // hold the XML data.
- fileURL = CFURLCreateWithFileSystemPath( kCFAllocatorDefault,
- filePath,
- kCFURLPOSIXPathStyle,
- false /* not a directory */ );
- if (fileURL == NULL) {
- errx(1, "Could not create file path URL");
+ if (fstat(fd, &sb) == -1) {
+ errx(1, "Could not fstat %s: %s", fileName, strerror(errno));
}
- CFRelease(filePath);
+ if (sb.st_size > UINT32_MAX) {
+ errx(1, "too big for our purposes");
+ }
- if (! CFURLCreateDataAndPropertiesFromResource(
- kCFAllocatorDefault,
- fileURL,
- &data,
- NULL,
- NULL,
- &errorCode) || data == NULL ) {
- errx(1, "Error reading XML file (%d)", (int)errorCode);
+ buffer = malloc((size_t)sb.st_size);
+ if (buffer == NULL) {
+ errx(1, "Could not allocate buffer");
}
- CFRelease(fileURL);
+ if (read(fd, buffer, (size_t)sb.st_size) != sb.st_size) {
+ errx(1, "Could not read %s: %s", fileName, strerror(errno));
+ }
- plist = CFPropertyListCreateFromXMLData(kCFAllocatorDefault,
- data,
- kCFPropertyListImmutable,
- &errorString);
+ close(fd);
- CFRelease(data);
+ stream = CFReadStreamCreateWithBytesNoCopy(kCFAllocatorDefault,
+ (const UInt8 *)buffer,
+ (CFIndex)sb.st_size,
+ kCFAllocatorNull);
+ if (stream == NULL) {
+ errx(1, "Could not create stream from serialized data");
+ }
+
+ if (!CFReadStreamOpen(stream)) {
+ errx(1, "Could not open the stream");
+ }
+
+ plist = CFPropertyListCreateWithStream(kCFAllocatorDefault,
+ stream,
+ (CFIndex)sb.st_size,
+ kCFPropertyListImmutable,
+ &format,
+ NULL);
if (plist == NULL) {
errx(1, "Error parsing XML file");
}
- if (errorString != NULL) {
- errx(1, "Error parsing XML file: %s", CFStringGetCStringPtr(errorString, kCFStringEncodingUTF8));
- }
+ CFReadStreamClose(stream);
+
+ CFRelease(stream);
+
+ free(buffer);
CFDictionaryApplyFunction(plist, &SetOFVariableFromFile, 0);
CFStringRef nameRef;
CFTypeRef valueRef;
kern_return_t result;
-
+
// OF variable name is first.
name = str;
-
+
// Find the equal sign for set
while (*str) {
if (*str == '=') {
}
str++;
}
-
+
if (set == 1) {
// On sets, the OF variable's value follows the equal sign.
value = str;
-
- result = SetOFVariable(name, value);
- NVRamSyncNow(name); /* Try syncing the new data to device, best effort! */
+#if TARGET_OS_BRIDGE
+ if (gBridgeToIntel) {
+ result = SetMacOFVariable(name, value);
+ }
+ else
+#endif
+ {
+ result = SetOFVariable(name, value);
+ NVRamSyncNow(name); /* Try syncing the new data to device, best effort! */
+ }
if (result != KERN_SUCCESS) {
errx(1, "Error setting variable - '%s': %s", name,
mach_error_string(result));
}
} else {
- result = GetOFVariable(name, &nameRef, &valueRef);
- if (result != KERN_SUCCESS) {
- errx(1, "Error getting variable - '%s': %s", name,
- mach_error_string(result));
+#if TARGET_OS_BRIDGE
+ if (gBridgeToIntel) {
+ result = GetMacOFVariable(name, &value);
+ if (result != KERN_SUCCESS) {
+ errx(1, "Error getting variable - '%s': %s", name,
+ mach_error_string(result));
+ }
+ nameRef = CFStringCreateWithCString(kCFAllocatorDefault, name, kCFStringEncodingUTF8);
+ valueRef = CFStringCreateWithCString(kCFAllocatorDefault, value, kCFStringEncodingUTF8);
+ }
+ else
+#endif
+ {
+ result = GetOFVariable(name, &nameRef, &valueRef);
+ if (result != KERN_SUCCESS) {
+ errx(1, "Error getting variable - '%s': %s", name,
+ mach_error_string(result));
+ }
}
-
+
PrintOFVariable(nameRef, valueRef, 0);
CFRelease(nameRef);
CFRelease(valueRef);
}
}
+#if TARGET_OS_BRIDGE
+static kern_return_t LinkMacNVRAMSymbols()
+{
+ gDL_handle = dlopen("libMacEFIHostInterface.dylib", RTLD_LAZY);
+ if (gDL_handle == NULL) {
+ errx(errno, "Failed to dlopen libMacEFIHostInterface.dylib");
+ return KERN_FAILURE; /* NOTREACHED */
+ }
+
+ hostInterfaceInitialize_fptr = dlsym(gDL_handle, "hostInterfaceInitialize");
+ if (hostInterfaceInitialize_fptr == NULL) {
+ errx(errno, "failed to link hostInterfaceInitialize");
+ }
+ createNvramHostInterface_fptr = dlsym(gDL_handle, "createNvramHostInterface");
+ if (createNvramHostInterface_fptr == NULL) {
+ errx(errno, "failed to link createNvramHostInterface");
+ }
+ destroyNvramHostInterface_fptr = dlsym(gDL_handle, "destroyNvramHostInterface");
+ if (destroyNvramHostInterface_fptr == NULL) {
+ errx(errno, "failed to link destroyNvramHostInterface");
+ }
+ getNVRAMVariable_fptr = dlsym(gDL_handle, "getNVRAMVariable");
+ if (getNVRAMVariable_fptr == NULL) {
+ errx(errno, "failed to link getNVRAMVariable");
+ }
+ setNVRAMVariable_fptr = dlsym(gDL_handle, "setNVRAMVariable");
+ if (setNVRAMVariable_fptr == NULL) {
+ errx(errno, "failed to link setNVRAMVariable");
+ }
+ hostInterfaceDeinitialize_fptr = dlsym(gDL_handle, "hostInterfaceDeinitialize");
+ if (hostInterfaceDeinitialize_fptr == NULL) {
+ errx(errno, "failed to link hostInterfaceDeinitialize");
+ }
+
+ /* also do the initialization */
+ hostInterfaceInitialize_fptr();
+ gNvramInterface = createNvramHostInterface_fptr(NULL);
+
+ return KERN_SUCCESS;
+}
+#endif
// GetOFVariable(name, nameRef, valueRef)
//
if (*nameRef == 0) {
errx(1, "Error creating CFString for key %s", name);
}
-
+
*valueRef = IORegistryEntryCreateCFProperty(gOptionsRef, *nameRef, 0, 0);
if (*valueRef == 0) return kIOReturnNotFound;
-
+
return KERN_SUCCESS;
}
+#if TARGET_OS_BRIDGE
+// GetMacOFVariable(name, value)
+//
+// Get the named firmware variable from the Intel side.
+// Return the value in value
+//
+static kern_return_t GetMacOFVariable(char *name, char **value)
+{
+ uint32_t value_size;
+ kern_return_t result = KERN_FAILURE;
+ assert(getNVRAMVariable_fptr != NULL);
+
+ result = getNVRAMVariable_fptr(gNvramInterface, name, value, &value_size);
+
+ return result;
+}
+#endif
// SetOFVariable(name, value)
//
CFTypeRef valueRef;
CFTypeID typeID;
kern_return_t result = KERN_SUCCESS;
-
+
nameRef = CFStringCreateWithCString(kCFAllocatorDefault, name,
kCFStringEncodingUTF8);
if (nameRef == 0) {
errx(1, "Error creating CFString for key %s", name);
}
-
+
valueRef = IORegistryEntryCreateCFProperty(gOptionsRef, nameRef, 0, 0);
if (valueRef) {
typeID = CFGetTypeID(valueRef);
CFRelease(valueRef);
-
+
valueRef = ConvertValueToCFTypeRef(typeID, value);
if (valueRef == 0) {
errx(1, "Error creating CFTypeRef for value %s", value);
} result = IORegistryEntrySetCFProperty(gOptionsRef, nameRef, valueRef);
} else {
while (1) {
- // In the default case, try data, string, number, then boolean.
-
+ // In the default case, try data, string, number, then boolean.
+
valueRef = ConvertValueToCFTypeRef(CFDataGetTypeID(), value);
if (valueRef != 0) {
result = IORegistryEntrySetCFProperty(gOptionsRef, nameRef, valueRef);
if (result == KERN_SUCCESS) break;
}
-
+
valueRef = ConvertValueToCFTypeRef(CFStringGetTypeID(), value);
if (valueRef != 0) {
result = IORegistryEntrySetCFProperty(gOptionsRef, nameRef, valueRef);
if (result == KERN_SUCCESS) break;
}
-
+
valueRef = ConvertValueToCFTypeRef(CFNumberGetTypeID(), value);
if (valueRef != 0) {
result = IORegistryEntrySetCFProperty(gOptionsRef, nameRef, valueRef);
if (result == KERN_SUCCESS) break;
}
-
+
valueRef = ConvertValueToCFTypeRef(CFBooleanGetTypeID(), value);
if (valueRef != 0) {
result = IORegistryEntrySetCFProperty(gOptionsRef, nameRef, valueRef);
if (result == KERN_SUCCESS) break;
}
-
+
break;
}
}
-
+
CFRelease(nameRef);
-
+
return result;
}
+#if TARGET_OS_BRIDGE
+static kern_return_t SetMacOFVariable(char *name, char *value)
+{
+ kern_return_t result = KERN_FAILURE;
+ assert(setNVRAMVariable_fptr != NULL);
+
+ result = setNVRAMVariable_fptr(gNvramInterface, name, value, strlen(value));
+
+ return result;
+}
+#endif
// DeleteOFVariable(name)
//
// Delete the named firmware variable.
-//
+//
//
static void DeleteOFVariable(char *name)
{
SetOFVariable(kIONVRAMDeletePropertyKey, name);
}
+#if TARGET_OS_BRIDGE
+static void DeleteMacOFVariable(char *name)
+{
+ /* Not yet implementable */
+}
+#endif
+
static void NVRamSyncNow(char *name)
{
- SetOFVariable(kIONVRAMSyncNowPropertyKey, name);
+ if (!gUseForceSync) {
+ SetOFVariable(kIONVRAMSyncNowPropertyKey, name);
+ } else {
+ SetOFVariable(kIONVRAMForceSyncNowPropertyKey, name);
+ }
}
// PrintOFVariables()
//
// Print all of the firmware variables.
//
-static void PrintOFVariables()
+static void PrintOFVariables(void)
{
kern_return_t result;
CFMutableDictionaryRef dict;
-
+
result = IORegistryEntryCreateCFProperties(gOptionsRef, &dict, 0, 0);
if (result != KERN_SUCCESS) {
errx(1, "Error getting the firmware variables: %s", mach_error_string(result));
if (gUseXML) {
CFDataRef data;
- data = CFPropertyListCreateXMLData( kCFAllocatorDefault, dict );
+ data = CFPropertyListCreateData( kCFAllocatorDefault, dict, kCFPropertyListXMLFormat_v1_0, 0, NULL );
if (data == NULL) {
errx(1, "Error converting variables to xml");
}
CFDictionaryApplyFunction(dict, &PrintOFVariable, 0);
}
-
+
CFRelease(dict);
}
CFIndex valueLen;
char *valueBuffer = 0;
const char *valueString = 0;
- uint32_t number, length;
+ uint32_t number;
+ long length;
CFTypeID typeID;
-
+
+ if (gUseXML) {
+ CFDataRef data;
+ CFDictionaryRef dict = CFDictionaryCreate(kCFAllocatorDefault, &key, &value, 1,
+ &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ if (dict == NULL) {
+ errx(1, "Error creating dictionary for variable value");
+ }
+
+ data = CFPropertyListCreateData( kCFAllocatorDefault, dict, kCFPropertyListXMLFormat_v1_0, 0, NULL );
+ if (data == NULL) {
+ errx(1, "Error creating xml plist for variable");
+ }
+
+ fwrite(CFDataGetBytePtr(data), sizeof(UInt8), CFDataGetLength(data), stdout);
+
+ CFRelease(dict);
+ CFRelease(data);
+ return;
+ }
+
// Get the OF variable's name.
nameLen = CFStringGetLength(key) + 1;
nameBuffer = malloc(nameLen);
warnx("Unable to convert property name to C string");
nameString = "<UNPRINTABLE>";
}
-
+
// Get the OF variable's type.
typeID = CFGetTypeID(value);
-
+
if (typeID == CFBooleanGetTypeID()) {
if (CFBooleanGetValue(value)) valueString = "true";
else valueString = "false";
} else {
valueString="<INVALID>";
}
-
+
if ((nameString != 0) && (valueString != 0))
printf("%s\t%s\n", nameString, valueString);
-
+
if (dataBuffer != 0) free(dataBuffer);
if (nameBuffer != 0) free(nameBuffer);
if (valueBuffer != 0) free(valueBuffer);
CFTypeRef valueRef = 0;
long cnt, cnt2, length;
unsigned long number, tmp;
-
+
if (typeID == CFBooleanGetTypeID()) {
if (!strcmp("true", value)) valueRef = kCFBooleanTrue;
else if (!strcmp("false", value)) valueRef = kCFBooleanFalse;
valueRef = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (const UInt8 *)value,
cnt2, kCFAllocatorDefault);
} else return 0;
-
+
return valueRef;
}
result = IORegistryEntrySetCFProperty(gOptionsRef, key, value);
if ( result != KERN_SUCCESS ) {
- int nameLen;
+ long nameLen;
char *nameBuffer;
char *nameString;