2023-08-31 22:12:58 +02:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2000-2020 Apple Inc. All rights reserved.
|
|
|
|
*
|
|
|
|
* @APPLE_LICENSE_HEADER_START@
|
|
|
|
*
|
|
|
|
* The contents of this file constitute Original Code as defined in and
|
|
|
|
* are subject to the Apple Public Source License Version 1.1 (the
|
|
|
|
* "License"). You may not use this file except in compliance with the
|
|
|
|
* License. Please obtain a copy of the License at
|
|
|
|
* http://www.apple.com/publicsource and read it before using this file.
|
|
|
|
*
|
|
|
|
* This Original Code and all software distributed under the License are
|
|
|
|
* distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
|
|
|
|
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
|
|
|
|
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
|
|
|
|
* License for the specific language governing rights and limitations
|
|
|
|
* under the License.
|
|
|
|
*
|
|
|
|
* @APPLE_LICENSE_HEADER_END@
|
|
|
|
*/
|
|
|
|
/*
|
|
|
|
cc -o nvram nvram.c -framework CoreFoundation -framework IOKit -Wall
|
|
|
|
*/
|
|
|
|
// https://github.com/apple-oss-distributions/system_cmds/blob/13d383ddb305dc1672243e5384ba18b58949cc2c/nvram.tproj/nvram.c
|
|
|
|
|
|
|
|
|
|
|
|
//#include "assumes.h"
|
|
|
|
#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>
|
|
|
|
|
|
|
|
#define TARGET_OS_BRIDGE 0
|
|
|
|
|
|
|
|
// properties found in the registry root
|
|
|
|
#define kIOConsoleUsersKey "IOConsoleUsers" /* value is OSArray */
|
|
|
|
#define kIOMaximumMappedIOByteCountKey "IOMaximumMappedIOByteCount" /* value is OSNumber */
|
|
|
|
|
|
|
|
// properties found in the console user dict
|
|
|
|
|
|
|
|
#define kIOConsoleSessionIDKey "kCGSSessionIDKey" /* value is OSNumber */
|
|
|
|
|
|
|
|
#define kIOConsoleSessionUserNameKey "kCGSSessionUserNameKey" /* value is OSString */
|
|
|
|
#define kIOConsoleSessionUIDKey "kCGSSessionUserIDKey" /* value is OSNumber */
|
|
|
|
#define kIOConsoleSessionConsoleSetKey "kCGSSessionConsoleSetKey" /* value is OSNumber */
|
|
|
|
#define kIOConsoleSessionOnConsoleKey "kCGSSessionOnConsoleKey" /* value is OSBoolean */
|
|
|
|
|
|
|
|
// IOResources property
|
|
|
|
#define kIOConsoleUsersSeedKey "IOConsoleUsersSeed" /* value is OSNumber */
|
|
|
|
|
|
|
|
#define kIOKernelHasSafeSleep 1
|
|
|
|
#define kIONVRAMForceSyncNowPropertyKey "IONVRAM-FORCESYNCNOW-PROPERTY"
|
|
|
|
|
|
|
|
#define gEfiGlobalVariableGuid "8BE4DF61-93CA-11D2-AA0D-00E098032B8C"
|
|
|
|
#define gAppleNvramGuid "4D1EDE05-38C7-4A6A-9CC6-4BCCA8B38C14"
|
|
|
|
#define gAppleSecureBootGuid "94B73556-2197-4702-82A8-3E1337DAFBFB"
|
|
|
|
#define gAppleBootGuid "7C436110-AB2A-4BBB-A880-FE41995C9F82"
|
|
|
|
#define gAppleNetworkGuid "36C28AB5-6566-4C50-9EBD-CBB920F83843"
|
|
|
|
|
|
|
|
// Prototypes
|
|
|
|
static void UsageMessage(const char *message);
|
|
|
|
static void ParseFile(const char *fileName);
|
|
|
|
static void ParseXMLFile(const char *fileName);
|
|
|
|
static void SetOrGetOFVariable(char *str);
|
|
|
|
static kern_return_t GetOFVariable(const char *name, CFStringRef *nameRef,
|
|
|
|
CFTypeRef *valueRef);
|
|
|
|
static kern_return_t SetOFVariable(const char *name, const char *value);
|
|
|
|
static void DeleteOFVariable(const char *name);
|
|
|
|
static void PrintOFVariables(void);
|
|
|
|
static void PrintOFLargestVariables(void);
|
|
|
|
static void PrintOFVariable(const void *key,const void *value,void *context);
|
|
|
|
static void SetOFVariableFromFile(const void *key, const void *value, void *context);
|
|
|
|
static int ClearOFVariables(void);
|
|
|
|
static void ClearOFVariable(const void *key,const void *value,void *context);
|
|
|
|
static CFTypeRef ConvertValueToCFTypeRef(CFTypeID typeID, const char *value);
|
|
|
|
|
|
|
|
static void NVRamSyncNow(void);
|
|
|
|
|
|
|
|
// Global Variables
|
|
|
|
static io_registry_entry_t gOptionsRef;
|
|
|
|
static io_registry_entry_t gSystemOptionsRef;
|
|
|
|
static io_registry_entry_t gSelectedOptionsRef;
|
|
|
|
static bool gUseXML;
|
|
|
|
static bool gPrintInHex;
|
|
|
|
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 kern_return_t 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);
|
|
|
|
static kern_return_t (*deleteNVRAMVariable_fptr)(void *interface, char *name);
|
|
|
|
static void (*hostInterfaceDeinitialize_fptr)(void); /* may not need? */
|
|
|
|
|
|
|
|
#endif /* TARGET_OS_BRIDGE */
|
|
|
|
|
|
|
|
int main(int argc, char **argv)
|
|
|
|
{
|
|
|
|
long cnt;
|
|
|
|
char *str, errorMessage[256];
|
|
|
|
kern_return_t result;
|
|
|
|
mach_port_t mainPort;
|
|
|
|
int argcount = 0;
|
|
|
|
|
2023-09-01 22:08:13 +02:00
|
|
|
|
|
|
|
#if defined(MAC_OS_VERSION_12_0)
|
|
|
|
result = IOMainPort(bootstrap_port, &mainPort);
|
|
|
|
#else
|
|
|
|
result = IOMasterPort(bootstrap_port, &mainPort);
|
|
|
|
#endif
|
2023-08-31 22:12:58 +02:00
|
|
|
if (result != KERN_SUCCESS) {
|
|
|
|
errx(1, "Error getting the IOMainPort: %s",
|
|
|
|
mach_error_string(result));
|
|
|
|
}
|
|
|
|
|
|
|
|
gOptionsRef = IORegistryEntryFromPath(mainPort, "IODeviceTree:/options");
|
|
|
|
if (gOptionsRef == 0) {
|
|
|
|
errx(1, "nvram is not supported on this system");
|
|
|
|
}
|
|
|
|
|
|
|
|
gSystemOptionsRef = IORegistryEntryFromPath(mainPort, "IOService:/options/options-system");
|
|
|
|
|
|
|
|
gSelectedOptionsRef = gOptionsRef;
|
|
|
|
|
|
|
|
for (cnt = 1; cnt < argc; cnt++) {
|
|
|
|
str = argv[cnt];
|
|
|
|
if (str[0] == '-' && str[1] != 0) {
|
|
|
|
// Parse the options.
|
|
|
|
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;
|
|
|
|
|
|
|
|
case 'h' :
|
|
|
|
UsageMessage("");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'x' :
|
|
|
|
if (gPrintInHex) {
|
|
|
|
fprintf(stderr, "-x not supported with -X hex mode.\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
gUseXML = true;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'X' :
|
|
|
|
if (gUseXML) {
|
|
|
|
fprintf(stderr, "-X hex mode not supported with -x XMLmode.\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
gPrintInHex = true;
|
|
|
|
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]);
|
|
|
|
} else {
|
|
|
|
UsageMessage("missing filename");
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'd':
|
|
|
|
cnt++;
|
|
|
|
if (cnt < argc && *argv[cnt] != '-') {
|
|
|
|
#if TARGET_OS_BRIDGE
|
|
|
|
if (gBridgeToIntel) {
|
|
|
|
if ((result = DeleteMacOFVariable(argv[cnt])) != KERN_SUCCESS) {
|
|
|
|
errx(1, "Error deleting variable - '%s': %s (0x%08x)", argv[cnt],
|
|
|
|
mach_error_string(result), result);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
DeleteOFVariable(argv[cnt]);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
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
|
|
|
|
result = 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':
|
|
|
|
// 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
|
|
|
|
|
|
|
|
case 'z':
|
|
|
|
// -z option is unadvertised -- attempts to use the options-system node
|
|
|
|
// to write to the system NVRAM region if available
|
|
|
|
if (gSystemOptionsRef) {
|
|
|
|
fprintf(stderr, "Selecting options-system node.\n");
|
|
|
|
gSelectedOptionsRef = gSystemOptionsRef;
|
|
|
|
} else {
|
|
|
|
fprintf(stderr, "No options-system node, using options.\n");
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
strcpy(errorMessage, "no such option as --");
|
|
|
|
errorMessage[strlen(errorMessage)-1] = *str;
|
|
|
|
UsageMessage(errorMessage);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Other arguments will be firmware variable requests.
|
|
|
|
argcount++;
|
|
|
|
SetOrGetOFVariable(str);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// radar:25206371
|
|
|
|
if (argcount == 0 && gUseForceSync == true) {
|
|
|
|
NVRamSyncNow();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (argc == 1) {
|
|
|
|
UsageMessage("no arguments specified");
|
|
|
|
}
|
|
|
|
|
|
|
|
IOObjectRelease(gOptionsRef);
|
|
|
|
|
|
|
|
if (gSystemOptionsRef) {
|
|
|
|
IOObjectRelease(gSystemOptionsRef);
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
// UsageMessage(message)
|
|
|
|
//
|
|
|
|
// Print the usage information and exit.
|
|
|
|
//
|
|
|
|
static void UsageMessage(const char *message)
|
|
|
|
{
|
|
|
|
warnx("(usage: %s)", message);
|
|
|
|
|
|
|
|
printf("nvram [-x|-X] [-p] [-f filename] [-d name] [-c] name[=value] ...\n");
|
|
|
|
printf("\t-x use XML format for printing or reading variables\n");
|
|
|
|
printf("\t (must appear before -p or -f)\n");
|
|
|
|
printf("\t-X use HEX format for printing or reading variables\n");
|
|
|
|
printf("\t (must appear before -p or -f)\n");
|
|
|
|
printf("\t-p print all firmware variables\n");
|
|
|
|
printf("\t-f set firmware variables from a text file\n");
|
|
|
|
printf("\t-d delete the named variable\n");
|
|
|
|
printf("\t-c delete all variables\n");
|
|
|
|
#if TARGET_OS_BRIDGE
|
|
|
|
printf("\t-m set nvram variables on macOS from bridgeOS\n");
|
|
|
|
#endif
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// States for ParseFile.
|
|
|
|
enum {
|
|
|
|
kFirstColumn = 0,
|
|
|
|
kScanComment,
|
|
|
|
kFindName,
|
|
|
|
kCollectName,
|
|
|
|
kFindValue,
|
|
|
|
kCollectValue,
|
|
|
|
kContinueValue,
|
|
|
|
kSetenv,
|
|
|
|
|
|
|
|
kMaxStringSize = 0x800,
|
|
|
|
kMaxNameSize = 0x100
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// ParseFile(fileName)
|
|
|
|
//
|
|
|
|
// Open and parse the specified file.
|
|
|
|
//
|
|
|
|
static void ParseFile(const char *fileName)
|
|
|
|
{
|
|
|
|
long state, ni = 0, vi = 0;
|
|
|
|
int tc;
|
|
|
|
char name[kMaxNameSize];
|
|
|
|
char value[kMaxStringSize];
|
|
|
|
FILE *patches;
|
|
|
|
kern_return_t kret;
|
|
|
|
|
|
|
|
if (gUseXML) {
|
|
|
|
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))
|
|
|
|
errx(1, "Name exceeded max length of %d", kMaxNameSize);
|
|
|
|
if(vi==(kMaxStringSize-1))
|
|
|
|
errx(1, "Value exceeded max length of %d", kMaxStringSize);
|
|
|
|
switch (state) {
|
|
|
|
case kFirstColumn :
|
|
|
|
ni = 0;
|
|
|
|
vi = 0;
|
|
|
|
if (tc == '#') {
|
|
|
|
state = kScanComment;
|
|
|
|
} else if (tc == '\n') {
|
|
|
|
// state stays kFirstColumn.
|
|
|
|
} else if (isspace(tc)) {
|
|
|
|
state = kFindName;
|
|
|
|
} else {
|
|
|
|
state = kCollectName;
|
|
|
|
name[ni++] = tc;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case kScanComment :
|
|
|
|
if (tc == '\n') {
|
|
|
|
state = kFirstColumn;
|
|
|
|
} else {
|
|
|
|
// state stays kScanComment.
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case kFindName :
|
|
|
|
if (tc == '\n') {
|
|
|
|
state = kFirstColumn;
|
|
|
|
} else if (isspace(tc)) {
|
|
|
|
// state stays kFindName.
|
|
|
|
} else {
|
|
|
|
state = kCollectName;
|
|
|
|
name[ni++] = tc;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case kCollectName :
|
|
|
|
if (tc == '\n') {
|
|
|
|
name[ni] = 0;
|
|
|
|
warnx("Name must be followed by white space - '%s'", name);
|
|
|
|
state = kFirstColumn;
|
|
|
|
} else if (isspace(tc)) {
|
|
|
|
state = kFindValue;
|
|
|
|
} else {
|
|
|
|
name[ni++] = tc;
|
|
|
|
// state staus kCollectName.
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case kFindValue :
|
|
|
|
case kContinueValue :
|
|
|
|
if (tc == '\n') {
|
|
|
|
state = kSetenv;
|
|
|
|
} else if (isspace(tc)) {
|
|
|
|
// state stays kFindValue or kContinueValue.
|
|
|
|
} else {
|
|
|
|
state = kCollectValue;
|
|
|
|
value[vi++] = tc;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case kCollectValue :
|
|
|
|
if (tc == '\n') {
|
|
|
|
if (value[vi-1] == '\\') {
|
|
|
|
value[vi-1] = '\r';
|
|
|
|
state = kContinueValue;
|
|
|
|
} else {
|
|
|
|
state = kSetenv;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// state stays kCollectValue.
|
|
|
|
value[vi++] = tc;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (state == kSetenv) {
|
|
|
|
name[ni] = 0;
|
|
|
|
value[vi] = 0;
|
|
|
|
if ((kret = SetOFVariable(name, value)) != KERN_SUCCESS) {
|
|
|
|
errx(1, "Error setting variable - '%s': %s", name,
|
|
|
|
mach_error_string(kret));
|
|
|
|
}
|
|
|
|
state = kFirstColumn;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (state != kFirstColumn) {
|
|
|
|
errx(1, "Last line ended abruptly");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ParseXMLFile(fileName)
|
|
|
|
//
|
|
|
|
// Open and parse the specified file in XML format,
|
|
|
|
// and set variables appropriately.
|
|
|
|
//
|
|
|
|
static void ParseXMLFile(const char *fileName)
|
|
|
|
{
|
|
|
|
CFPropertyListRef plist;
|
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fstat(fd, &sb) == -1) {
|
|
|
|
errx(1, "Could not fstat %s: %s", fileName, strerror(errno));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sb.st_size > UINT32_MAX) {
|
|
|
|
errx(1, "too big for our purposes");
|
|
|
|
}
|
|
|
|
|
|
|
|
buffer = malloc((size_t)sb.st_size);
|
|
|
|
if (buffer == NULL) {
|
|
|
|
errx(1, "Could not allocate buffer");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (read(fd, buffer, (size_t)sb.st_size) != sb.st_size) {
|
|
|
|
errx(1, "Could not read %s: %s", fileName, strerror(errno));
|
|
|
|
}
|
|
|
|
|
|
|
|
close(fd);
|
|
|
|
|
|
|
|
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");
|
|
|
|
}
|
|
|
|
|
|
|
|
CFReadStreamClose(stream);
|
|
|
|
|
|
|
|
CFRelease(stream);
|
|
|
|
|
|
|
|
free(buffer);
|
|
|
|
|
|
|
|
CFDictionaryApplyFunction(plist, &SetOFVariableFromFile, 0);
|
|
|
|
|
|
|
|
CFRelease(plist);
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetOrGetOFVariable(str)
|
|
|
|
//
|
|
|
|
// Parse the input string, then set, append or get
|
|
|
|
// the specified firmware variable.
|
|
|
|
//
|
|
|
|
static void SetOrGetOFVariable(char *str)
|
|
|
|
{
|
|
|
|
long set = 0;
|
|
|
|
long append = 0;
|
|
|
|
long remove = 0;
|
|
|
|
const char *name = NULL;
|
|
|
|
char *value = NULL;
|
|
|
|
char *substring = NULL;
|
|
|
|
char *tmp = NULL;
|
|
|
|
CFStringRef nameRef = NULL;
|
|
|
|
CFTypeRef valueRef = NULL;
|
|
|
|
size_t len = 0;
|
|
|
|
CFMutableDataRef mutableValueRef = NULL;
|
|
|
|
kern_return_t result;
|
|
|
|
|
|
|
|
// OF variable name is first.
|
|
|
|
name = str;
|
|
|
|
|
|
|
|
// Find the equal sign for set, += for append, -= for trim
|
|
|
|
while (*str) {
|
|
|
|
if (*str == '+' && *(str+1) == '=') {
|
|
|
|
append = 1;
|
|
|
|
*str++ = '\0';
|
|
|
|
*str++ = '\0';
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*str == '-' && *(str+1) == '=') {
|
|
|
|
remove = 1;
|
|
|
|
*str++ = '\0';
|
|
|
|
*str++ = '\0';
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*str == '=') {
|
|
|
|
set = 1;
|
|
|
|
*str++ = '\0';
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
str++;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read the current value if appending or if no =/+=
|
|
|
|
if (append == 1 || remove == 1 || (set == 0 && append == 0 && remove == 0)) {
|
|
|
|
#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);
|
|
|
|
free(value);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
result = GetOFVariable(name, &nameRef, &valueRef);
|
|
|
|
if (result != KERN_SUCCESS) {
|
|
|
|
errx(1, "Error getting variable - '%s': %s", name,
|
|
|
|
mach_error_string(result));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (set == 1) {
|
|
|
|
// On sets, the OF variable's value follows the equal sign.
|
|
|
|
value = str;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (append == 1) {
|
|
|
|
// On append, the value to append follows the += substring
|
|
|
|
if(CFGetTypeID(valueRef) == CFStringGetTypeID()) {
|
|
|
|
len = strlen(str);
|
|
|
|
len += CFStringGetMaximumSizeForEncoding(CFStringGetLength(valueRef),
|
|
|
|
kCFStringEncodingUTF8);
|
|
|
|
tmp = calloc(len + 1, 1);
|
|
|
|
if ( (tmp == NULL)
|
|
|
|
|| (CFStringGetCString(valueRef, tmp, len, kCFStringEncodingUTF8) == false)) {
|
|
|
|
errx(1, "allocation failed");
|
|
|
|
}
|
|
|
|
|
|
|
|
value = tmp;
|
|
|
|
strcpy(value + strlen(value), str);
|
|
|
|
} else if(CFGetTypeID(valueRef) == CFDataGetTypeID()) {
|
|
|
|
mutableValueRef = CFDataCreateMutableCopy(kCFAllocatorDefault,
|
|
|
|
CFDataGetLength(valueRef) +
|
|
|
|
strlen(str) + 1,
|
|
|
|
valueRef);
|
|
|
|
CFDataAppendBytes(mutableValueRef, (const UInt8 *)str, strlen(str) + 1);
|
|
|
|
value = (char *)CFDataGetBytePtr(mutableValueRef);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
errx(1, "Unsupported named variable CFTypeID");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (remove == 1) {
|
|
|
|
// On remove, the value to remove follows the -= substring
|
|
|
|
if(CFGetTypeID(valueRef) == CFStringGetTypeID()) {
|
|
|
|
len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(valueRef),
|
|
|
|
kCFStringEncodingUTF8);
|
|
|
|
tmp = calloc(len + 1, 1);
|
|
|
|
if( (tmp == NULL)
|
|
|
|
|| (CFStringGetCString(valueRef, tmp, len, kCFStringEncodingUTF8) == false)) {
|
|
|
|
errx(1, "failed to allocate string");
|
|
|
|
}
|
|
|
|
|
|
|
|
value = tmp;
|
|
|
|
} else if(CFGetTypeID(valueRef) == CFDataGetTypeID()) {
|
|
|
|
value = (char *)CFDataGetBytePtr(valueRef);
|
|
|
|
} else {
|
|
|
|
errx(1, "Unsupported named variable CFTypeID");
|
|
|
|
}
|
|
|
|
|
|
|
|
substring = strstr(value, str);
|
|
|
|
if (substring == NULL) {
|
|
|
|
errx(1, "substring %s not found in %s\n", str, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
len = strlen(str);
|
|
|
|
memmove(substring, substring + len, strlen(substring + len) + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (set == 1 || append == 1 || remove == 1) {
|
|
|
|
#if TARGET_OS_BRIDGE
|
|
|
|
if (gBridgeToIntel) {
|
|
|
|
result = SetMacOFVariable(name, value);
|
|
|
|
if (result != KERN_SUCCESS) {
|
|
|
|
errx(1, "Error setting variable - '%s': %s", name,
|
|
|
|
mach_error_string(result));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
result = SetOFVariable(name, value);
|
|
|
|
// Try syncing the new data to device, best effort!
|
|
|
|
NVRamSyncNow();
|
|
|
|
if (result != KERN_SUCCESS) {
|
|
|
|
fprintf(stderr, "Error setting variable - '%s': %s.\n", name,
|
|
|
|
mach_error_string(result));
|
|
|
|
if (result == kIOReturnNoMemory) {
|
|
|
|
PrintOFLargestVariables();
|
|
|
|
}
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
PrintOFVariable(nameRef, valueRef, 0);
|
|
|
|
}
|
|
|
|
if (nameRef) CFRelease(nameRef);
|
|
|
|
if (valueRef) CFRelease(valueRef);
|
|
|
|
if (tmp) free(tmp);
|
|
|
|
if (mutableValueRef) CFRelease(mutableValueRef);
|
|
|
|
}
|
|
|
|
|
|
|
|
#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");
|
|
|
|
}
|
|
|
|
deleteNVRAMVariable_fptr = dlsym(gDL_handle, "deleteNVRAMVariable");
|
|
|
|
if (deleteNVRAMVariable_fptr == NULL) {
|
|
|
|
errx(errno, "failed to link deleteNVRAMVariable");
|
|
|
|
}
|
|
|
|
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)
|
|
|
|
//
|
|
|
|
// Get the named firmware variable.
|
|
|
|
// Return it and it's symbol in valueRef and nameRef.
|
|
|
|
//
|
|
|
|
static kern_return_t GetOFVariable(const char *name, CFStringRef *nameRef,
|
|
|
|
CFTypeRef *valueRef)
|
|
|
|
{
|
|
|
|
*nameRef = CFStringCreateWithCString(kCFAllocatorDefault, name,
|
|
|
|
kCFStringEncodingUTF8);
|
|
|
|
if (*nameRef == 0) {
|
|
|
|
errx(1, "Error creating CFString for key %s", name);
|
|
|
|
}
|
|
|
|
|
|
|
|
*valueRef = IORegistryEntryCreateCFProperty(gSelectedOptionsRef, *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;
|
|
|
|
|
|
|
|
return getNVRAMVariable_fptr(gNvramInterface, name, value, &value_size);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// SetOFVariable(name, value)
|
|
|
|
//
|
|
|
|
// Set or create an firmware variable with name and value.
|
|
|
|
//
|
|
|
|
static kern_return_t SetOFVariable(const char *name, const char *value)
|
|
|
|
{
|
|
|
|
CFStringRef nameRef;
|
|
|
|
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(gSelectedOptionsRef, 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(gSelectedOptionsRef, nameRef, valueRef);
|
|
|
|
} else {
|
|
|
|
// In the default case, try data, string, number, then boolean.
|
|
|
|
CFTypeID types[] = {CFDataGetTypeID(),
|
|
|
|
CFStringGetTypeID(), CFNumberGetTypeID(),CFBooleanGetTypeID() };
|
|
|
|
for (int i = 0; i < sizeof(types)/sizeof(types[0]); i++) {
|
|
|
|
valueRef = ConvertValueToCFTypeRef(types[i], value);
|
|
|
|
if (valueRef != 0) {
|
|
|
|
result = IORegistryEntrySetCFProperty(gSelectedOptionsRef, nameRef, valueRef);
|
|
|
|
if (result == KERN_SUCCESS || result == kIOReturnNoMemory || result == kIOReturnNoSpace) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CFRelease(nameRef);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if TARGET_OS_BRIDGE
|
|
|
|
static kern_return_t SetMacOFVariable(char *name, char *value)
|
|
|
|
{
|
|
|
|
return setNVRAMVariable_fptr(gNvramInterface, name, value);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// DeleteOFVariable(name)
|
|
|
|
//
|
|
|
|
// Delete the named firmware variable.
|
|
|
|
//
|
|
|
|
static void DeleteOFVariable(const char *name)
|
|
|
|
{
|
|
|
|
SetOFVariable(kIONVRAMDeletePropertyKey, name);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if TARGET_OS_BRIDGE
|
|
|
|
static kern_return_t DeleteMacOFVariable(char *name)
|
|
|
|
{
|
|
|
|
return deleteNVRAMVariable_fptr(gNvramInterface, name);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static void NVRamSyncNow(void)
|
|
|
|
{
|
|
|
|
if (!gUseForceSync) {
|
|
|
|
SetOFVariable(kIONVRAMSyncNowPropertyKey, kIONVRAMSyncNowPropertyKey);
|
|
|
|
} else {
|
|
|
|
SetOFVariable(kIONVRAMForceSyncNowPropertyKey, kIONVRAMForceSyncNowPropertyKey);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CFDictionaryRef CreateMyDictionary(void) {
|
|
|
|
|
|
|
|
// root
|
|
|
|
CFMutableDictionaryRef dict0 = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
|
|
|
|
&kCFTypeDictionaryKeyCallBacks,
|
|
|
|
&kCFTypeDictionaryValueCallBacks);
|
|
|
|
|
|
|
|
// APPLE_BOOT_VARIABLE_GUID
|
|
|
|
// Print all of the firmware variables.
|
|
|
|
CFMutableDictionaryRef dict1;
|
|
|
|
kern_return_t result;
|
|
|
|
result = IORegistryEntryCreateCFProperties(gOptionsRef, &dict1, 0, 0);
|
|
|
|
if (result != KERN_SUCCESS) {
|
|
|
|
errx(1, "Error getting the firmware variables: %s", mach_error_string(result));
|
|
|
|
}
|
|
|
|
CFDictionarySetValue(dict0, CFSTR(gAppleBootGuid), dict1);
|
|
|
|
CFRelease(dict1);
|
|
|
|
|
|
|
|
CFMutableDictionaryRef dict2 = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
|
|
|
|
&kCFTypeDictionaryValueCallBacks);
|
|
|
|
CFDictionarySetValue(dict0, CFSTR(gEfiGlobalVariableGuid), dict2);
|
|
|
|
|
|
|
|
// EFI_GLOBAL_VARIABLE_GUID
|
|
|
|
// Print the given firmware variable.
|
|
|
|
CFStringRef nameRef;
|
|
|
|
CFTypeRef valueRef;
|
|
|
|
|
|
|
|
const char *key[32];
|
|
|
|
char name[64];
|
|
|
|
CFStringRef var;
|
|
|
|
int i = 0;
|
|
|
|
int n = 0; // num of keys in this GUID
|
|
|
|
|
|
|
|
key[n++] = "Boot0080";
|
|
|
|
key[n++] = "BootOrder";
|
|
|
|
key[n++] = "BootNext";
|
|
|
|
key[n++] = "Boot0081";
|
|
|
|
key[n++] = "Boot0082";
|
|
|
|
key[n++] = "Boot0083";
|
|
|
|
key[n++] = "BootCurrent";
|
|
|
|
|
|
|
|
for ( i = 0; i < n; i++ ) {
|
|
|
|
snprintf(name, sizeof(name), "%s:%s", gEfiGlobalVariableGuid, key[i]);
|
|
|
|
var = CFStringCreateWithCString(NULL, key[i], kCFStringEncodingUTF8);
|
|
|
|
result = GetOFVariable(name, &nameRef, &valueRef);
|
|
|
|
if (result == KERN_SUCCESS) {
|
|
|
|
CFDictionaryAddValue (dict2, var, valueRef);
|
|
|
|
CFRelease(valueRef);
|
|
|
|
}
|
|
|
|
CFRelease(nameRef);
|
|
|
|
}
|
|
|
|
CFRelease(dict2);
|
|
|
|
|
|
|
|
// APPLE_WIRELESS_NETWORK_VARIABLE_GUID
|
|
|
|
CFMutableDictionaryRef dict3 = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
|
|
|
|
&kCFTypeDictionaryValueCallBacks);
|
|
|
|
CFDictionarySetValue(dict0, CFSTR(gAppleNetworkGuid), dict3);
|
|
|
|
n = 0; // num of keys in this GUID
|
|
|
|
key[n++] = "current-network";
|
|
|
|
key[n++] = "preferred-count";
|
|
|
|
key[n++] = "preferred-networks";
|
|
|
|
|
|
|
|
|
|
|
|
for ( i = 0; i < n; i++ ) {
|
|
|
|
snprintf(name, sizeof(name), "%s:%s", gAppleNetworkGuid, key[i]);
|
|
|
|
var = CFStringCreateWithCString(NULL, key[i], kCFStringEncodingUTF8);
|
|
|
|
result = GetOFVariable(name, &nameRef, &valueRef);
|
|
|
|
if (result == KERN_SUCCESS) {
|
|
|
|
CFDictionaryAddValue (dict3, var, valueRef);
|
|
|
|
CFRelease(valueRef);
|
|
|
|
}
|
|
|
|
CFRelease(nameRef);
|
|
|
|
}
|
|
|
|
CFRelease(dict3);
|
|
|
|
|
|
|
|
// APPLE_SECURE_BOOT_VARIABLE_GUID
|
|
|
|
CFMutableDictionaryRef dict4 = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
|
|
|
|
&kCFTypeDictionaryValueCallBacks);
|
|
|
|
CFDictionarySetValue(dict0, CFSTR(gAppleSecureBootGuid), dict4);
|
|
|
|
n = 0; // num of keys in this GUID
|
|
|
|
key[n++] = "ApECID";
|
|
|
|
key[n++] = "ApChipID";
|
|
|
|
key[n++] = "ApBoardID";
|
|
|
|
key[n++] = "ApSecurityDomain";
|
|
|
|
key[n++] = "ApProductionStatus";
|
|
|
|
key[n++] = "ApSecurityMode";
|
|
|
|
key[n++] = "EffectiveProductionStatus";
|
|
|
|
key[n++] = "EffectiveSecurityMode";
|
|
|
|
key[n++] = "CertificateEpoch";
|
|
|
|
key[n++] = "MixNMatchPreventionStatus";
|
|
|
|
key[n++] = "CryptoDigestMethod";
|
|
|
|
key[n++] = "HardwareModel";
|
|
|
|
key[n++] = "InternalUseOnlyUnit";
|
|
|
|
|
|
|
|
|
|
|
|
for ( i = 0; i < n; i++ ) {
|
|
|
|
snprintf(name, sizeof(name), "%s:%s", gAppleSecureBootGuid, key[i]);
|
|
|
|
var = CFStringCreateWithCString(NULL, key[i], kCFStringEncodingUTF8);
|
|
|
|
result = GetOFVariable(name, &nameRef, &valueRef);
|
|
|
|
if (result == KERN_SUCCESS) {
|
|
|
|
CFDictionaryAddValue (dict4, var, valueRef);
|
|
|
|
CFRelease(valueRef);
|
|
|
|
}
|
|
|
|
CFRelease(nameRef);
|
|
|
|
}
|
|
|
|
CFRelease(dict4);
|
|
|
|
|
|
|
|
CFMutableDictionaryRef dict5 = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
|
|
|
|
&kCFTypeDictionaryValueCallBacks);
|
|
|
|
CFDictionarySetValue(dict0, CFSTR(gAppleSecureBootGuid), dict5);
|
|
|
|
n=0;
|
|
|
|
key[n++] = "gfx-saved-config-restore-status";
|
|
|
|
key[n++] = "SkipLogo";
|
|
|
|
key[n++] = "IASCurrentInstallPhase";
|
2023-09-04 21:33:54 +02:00
|
|
|
key[n++] = "IASInstallPhaseList";
|
2023-08-31 22:12:58 +02:00
|
|
|
for ( i = 0; i < n; i++ ) {
|
|
|
|
snprintf(name, sizeof(name), "%s:%s", gAppleNvramGuid, key[i]);
|
|
|
|
var = CFStringCreateWithCString(NULL, key[i], kCFStringEncodingUTF8);
|
|
|
|
result = GetOFVariable(name, &nameRef, &valueRef);
|
|
|
|
if (result == KERN_SUCCESS) {
|
|
|
|
CFDictionaryAddValue (dict5, var, valueRef);
|
|
|
|
CFRelease(valueRef);
|
|
|
|
}
|
|
|
|
CFRelease(nameRef);
|
|
|
|
}
|
|
|
|
CFRelease(dict5);
|
|
|
|
|
|
|
|
return dict0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// PrintOFVariables()
|
|
|
|
//
|
|
|
|
// Print all of the firmware variables.
|
|
|
|
//
|
|
|
|
static void PrintOFVariables(void)
|
|
|
|
{
|
|
|
|
kern_return_t result;
|
|
|
|
CFMutableDictionaryRef dict;
|
|
|
|
|
|
|
|
result = IORegistryEntryCreateCFProperties(gSelectedOptionsRef, &dict, 0, 0);
|
|
|
|
if (result != KERN_SUCCESS) {
|
|
|
|
errx(1, "Error getting the firmware variables: %s", mach_error_string(result));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (gUseXML) {
|
|
|
|
CFDataRef data;
|
|
|
|
|
|
|
|
CFPropertyListRef propertyList = CreateMyDictionary();
|
|
|
|
data = CFPropertyListCreateData( kCFAllocatorDefault, propertyList, kCFPropertyListXMLFormat_v1_0, 0, NULL );
|
|
|
|
// data = CFPropertyListCreateData( kCFAllocatorDefault, dict, kCFPropertyListXMLFormat_v1_0, 0, NULL );
|
|
|
|
if (data == NULL) {
|
|
|
|
errx(1, "Error converting variables to xml");
|
|
|
|
}
|
|
|
|
|
|
|
|
fwrite(CFDataGetBytePtr(data), sizeof(UInt8), CFDataGetLength(data), stdout);
|
|
|
|
|
|
|
|
CFRelease(data);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
CFDictionaryApplyFunction(dict, &PrintOFVariable, 0);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
CFRelease(dict);
|
|
|
|
}
|
|
|
|
|
|
|
|
static size_t
|
|
|
|
ElementSize(const void *value)
|
|
|
|
{
|
|
|
|
CFTypeID typeId = CFGetTypeID(value);
|
|
|
|
if (typeId == CFStringGetTypeID()) {
|
|
|
|
return CFStringGetLength(value);
|
|
|
|
}
|
|
|
|
else if (typeId == CFDataGetTypeID()) {
|
|
|
|
return CFDataGetLength(value);
|
|
|
|
}
|
|
|
|
else if (typeId == CFNumberGetTypeID()) {
|
|
|
|
return 8;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// PrintOFLargestVariables()
|
|
|
|
//
|
|
|
|
// Print the LARGEST_COUNT largest
|
|
|
|
// nvram variables.
|
|
|
|
//
|
|
|
|
void
|
|
|
|
PrintOFLargestVariables(void)
|
|
|
|
{
|
|
|
|
#define LARGEST_COUNT 5
|
|
|
|
kern_return_t result;
|
|
|
|
CFMutableDictionaryRef dict;
|
|
|
|
long count;
|
|
|
|
void **keys, **values;
|
|
|
|
size_t *indices;
|
|
|
|
|
|
|
|
result = IORegistryEntryCreateCFProperties(gOptionsRef, &dict, 0, 0);
|
|
|
|
if (result != KERN_SUCCESS) {
|
|
|
|
errx(1, "Error getting the firmware variables: %s", mach_error_string(result));
|
|
|
|
}
|
|
|
|
|
|
|
|
count = CFDictionaryGetCount(dict);
|
|
|
|
|
|
|
|
keys = calloc(count, sizeof(void *));
|
|
|
|
//os_assert(keys != NULL);
|
|
|
|
values = calloc(count, sizeof(void *));
|
|
|
|
//os_assert(values != NULL);
|
|
|
|
|
|
|
|
indices = calloc(count, sizeof(*indices));
|
|
|
|
//os_assert(indices != NULL);
|
|
|
|
for (size_t i = 0; i < count; i++) {
|
|
|
|
indices[i] = i;
|
|
|
|
}
|
|
|
|
|
|
|
|
CFDictionaryGetKeysAndValues(dict, (const void **)keys, (const void **)values);
|
|
|
|
|
|
|
|
qsort_b(indices, count, sizeof(*indices), ^(const void *a, const void *b) {
|
|
|
|
return (int)(((int64_t)ElementSize(values[*(size_t*)b]) - (int64_t)(ElementSize(values[*(size_t*)a]))));
|
|
|
|
});
|
|
|
|
|
|
|
|
fprintf(stderr, "key\tbytes\n");
|
|
|
|
for (long i = 0; i < count && i < LARGEST_COUNT; i++) {
|
|
|
|
size_t size = ElementSize(values[indices[i]]);
|
|
|
|
if (size > 0) {
|
|
|
|
fprintf(stderr, "%s\t%zu\n", CFStringGetCStringPtr(keys[indices[i]], kCFStringEncodingUTF8
|
|
|
|
), size);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
free(keys);
|
|
|
|
free(values);
|
|
|
|
free(indices);
|
|
|
|
CFRelease(dict);
|
|
|
|
}
|
|
|
|
|
|
|
|
// PrintOFVariable(key, value, context)
|
|
|
|
//
|
|
|
|
// Print the given firmware variable.
|
|
|
|
//
|
|
|
|
static void PrintOFVariable(const void *key, const void *value, void *context)
|
|
|
|
{
|
|
|
|
long cnt, cnt2;
|
|
|
|
CFIndex nameLen;
|
|
|
|
char *nameBuffer = 0;
|
|
|
|
const char *nameString;
|
|
|
|
char numberBuffer[10];
|
|
|
|
const uint8_t *dataPtr;
|
|
|
|
uint8_t dataChar;
|
|
|
|
char *dataBuffer = 0;
|
|
|
|
CFIndex valueLen;
|
|
|
|
char *valueBuffer = 0;
|
|
|
|
const char *valueString = 0;
|
|
|
|
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 = CFStringGetMaximumSizeForEncoding(CFStringGetLength(key),
|
|
|
|
kCFStringEncodingUTF8) + 1;
|
|
|
|
nameBuffer = malloc(nameLen);
|
|
|
|
if( nameBuffer && CFStringGetCString(key, nameBuffer, nameLen, kCFStringEncodingUTF8) )
|
|
|
|
nameString = nameBuffer;
|
|
|
|
else {
|
|
|
|
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 if (typeID == CFNumberGetTypeID()) {
|
|
|
|
CFNumberGetValue(value, kCFNumberSInt32Type, &number);
|
|
|
|
if (number == 0xFFFFFFFF) sprintf(numberBuffer, "-1");
|
|
|
|
else if (!gPrintInHex && number < 1000) sprintf(numberBuffer, "%d", number);
|
|
|
|
else sprintf(numberBuffer, "0x%x", number);
|
|
|
|
valueString = numberBuffer;
|
|
|
|
} else if (typeID == CFStringGetTypeID()) {
|
|
|
|
valueLen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(value),
|
|
|
|
kCFStringEncodingUTF8) + 1;
|
|
|
|
valueBuffer = malloc(valueLen + 1);
|
|
|
|
if ( valueBuffer && CFStringGetCString(value, valueBuffer, valueLen, kCFStringEncodingUTF8) )
|
|
|
|
valueString = valueBuffer;
|
|
|
|
else {
|
|
|
|
warnx("Unable to convert value to C string");
|
|
|
|
valueString = "<UNPRINTABLE>";
|
|
|
|
}
|
|
|
|
} else if (typeID == CFDataGetTypeID()) {
|
|
|
|
length = CFDataGetLength(value);
|
|
|
|
if (length == 0) valueString = "";
|
|
|
|
else {
|
|
|
|
dataBuffer = malloc(length * 3 + 3);
|
|
|
|
if (dataBuffer != 0) {
|
|
|
|
dataPtr = CFDataGetBytePtr(value);
|
|
|
|
cnt = cnt2 = 0;
|
|
|
|
if (gPrintInHex) {
|
|
|
|
sprintf(dataBuffer, "0x");
|
|
|
|
cnt2 += 2;
|
|
|
|
}
|
|
|
|
for (; cnt < length; cnt++) {
|
|
|
|
dataChar = dataPtr[cnt];
|
|
|
|
if (gPrintInHex) {
|
|
|
|
sprintf(dataBuffer + cnt2, "%02x", dataChar);
|
|
|
|
cnt2 += 2;
|
|
|
|
} else if (!gPrintInHex && isprint(dataChar) && dataChar != '%') {
|
|
|
|
dataBuffer[cnt2++] = dataChar;
|
|
|
|
} else {
|
|
|
|
sprintf(dataBuffer + cnt2, "%%%02x", dataChar);
|
|
|
|
cnt2 += 3;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
dataBuffer[cnt2] = '\0';
|
|
|
|
valueString = dataBuffer;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} 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);
|
|
|
|
}
|
|
|
|
|
|
|
|
// ClearOFVariables()
|
|
|
|
//
|
|
|
|
// Deletes all OF variables
|
|
|
|
//
|
|
|
|
static int ClearOFVariables(void)
|
|
|
|
{
|
|
|
|
kern_return_t result;
|
|
|
|
CFMutableDictionaryRef dict;
|
|
|
|
|
|
|
|
result = IORegistryEntryCreateCFProperties(gSelectedOptionsRef, &dict, 0, 0);
|
|
|
|
if (result != KERN_SUCCESS) {
|
|
|
|
errx(1, "Error getting the firmware variables: %s", mach_error_string(result));
|
|
|
|
}
|
|
|
|
CFDictionaryApplyFunction(dict, &ClearOFVariable, &result);
|
|
|
|
|
|
|
|
CFRelease(dict);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ClearOFVariable(const void *key, const void *value, void *context)
|
|
|
|
{
|
|
|
|
kern_return_t result;
|
|
|
|
result = IORegistryEntrySetCFProperty(gSelectedOptionsRef,
|
|
|
|
CFSTR(kIONVRAMDeletePropertyKey), key);
|
|
|
|
if (result != KERN_SUCCESS) {
|
|
|
|
assert(CFGetTypeID(key) == CFStringGetTypeID());
|
|
|
|
const char *keyStr = CFStringGetCStringPtr(key, kCFStringEncodingUTF8);
|
|
|
|
char *keyBuffer = NULL;
|
|
|
|
size_t keyBufferLen = 0;
|
|
|
|
if (!keyStr) {
|
|
|
|
keyBufferLen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(key), kCFStringEncodingUTF8) + 1;
|
|
|
|
keyBuffer = (char *)malloc(keyBufferLen);
|
|
|
|
if (keyBuffer != NULL && CFStringGetCString(key, keyBuffer, keyBufferLen, kCFStringEncodingUTF8)) {
|
|
|
|
keyStr = keyBuffer;
|
|
|
|
} else {
|
|
|
|
warnx("Unable to convert property name to C string");
|
|
|
|
keyStr = "<UNPRINTABLE>";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
warnx("Error clearing firmware variable %s: %s", keyStr, mach_error_string(result));
|
|
|
|
if (keyBuffer) {
|
|
|
|
free(keyBuffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (context) {
|
|
|
|
*(int *)context = result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ConvertValueToCFTypeRef(typeID, value)
|
|
|
|
//
|
|
|
|
// Convert the value into a CFType given the typeID.
|
|
|
|
//
|
|
|
|
static CFTypeRef ConvertValueToCFTypeRef(CFTypeID typeID, const char *value)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
} else if (typeID == CFNumberGetTypeID()) {
|
|
|
|
number = strtol(value, 0, 0);
|
|
|
|
valueRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type,
|
|
|
|
&number);
|
|
|
|
} else if (typeID == CFStringGetTypeID()) {
|
|
|
|
valueRef = CFStringCreateWithCString(kCFAllocatorDefault, value,
|
|
|
|
kCFStringEncodingUTF8);
|
|
|
|
} else if (typeID == CFDataGetTypeID()) {
|
|
|
|
length = strlen(value);
|
|
|
|
char valueCopy[length + 1];
|
|
|
|
|
|
|
|
for (cnt = cnt2 = 0; cnt < length; cnt++, cnt2++) {
|
|
|
|
if (value[cnt] == '%') {
|
|
|
|
if ((cnt + 2 > length) ||
|
|
|
|
!ishexnumber(value[cnt + 1]) ||
|
|
|
|
!ishexnumber(value[cnt + 2])) return 0;
|
|
|
|
number = toupper(value[++cnt]) - '0';
|
|
|
|
if (number > 9) number -= 7;
|
|
|
|
tmp = toupper(value[++cnt]) - '0';
|
|
|
|
if (tmp > 9) tmp -= 7;
|
|
|
|
number = (number << 4) + tmp;
|
|
|
|
valueCopy[cnt2] = number;
|
|
|
|
} else valueCopy[cnt2] = value[cnt];
|
|
|
|
}
|
|
|
|
valueRef = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)valueCopy, cnt2);
|
|
|
|
} else return 0;
|
|
|
|
|
|
|
|
return valueRef;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void SetOFVariableFromFile(const void *key, const void *value, void *context)
|
|
|
|
{
|
|
|
|
kern_return_t result;
|
|
|
|
|
|
|
|
result = IORegistryEntrySetCFProperty(gSelectedOptionsRef, key, value);
|
|
|
|
if ( result != KERN_SUCCESS ) {
|
|
|
|
long nameLen;
|
|
|
|
char *nameBuffer;
|
|
|
|
char *nameString;
|
|
|
|
|
|
|
|
// Get the variable's name.
|
|
|
|
nameLen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(key),
|
|
|
|
kCFStringEncodingUTF8) + 1;
|
|
|
|
nameBuffer = malloc(nameLen);
|
|
|
|
if( nameBuffer && CFStringGetCString(key, nameBuffer, nameLen, kCFStringEncodingUTF8) )
|
|
|
|
nameString = nameBuffer;
|
|
|
|
else {
|
|
|
|
warnx("Unable to convert property name to C string");
|
|
|
|
nameString = "<UNPRINTABLE>";
|
|
|
|
}
|
|
|
|
errx(1, "Error setting variable - '%s': %s", nameString,
|
|
|
|
mach_error_string(result));
|
|
|
|
}
|
|
|
|
}
|