// /// @file rEFIt_UEFI/Platform/DataHubCpu.c /// /// VirtualBox CPU descriptors /// /// VirtualBox CPU descriptors also used to set OS X-used NVRAM variables and DataHub data /// // Copyright(C) 2009-2010 Oracle Corporation // // This file is part of VirtualBox Open Source Edition(OSE), as // available from http://www.virtualbox.org. This file is free software; // you can redistribute it and/or modify it under the terms of the GNU // General Public License(GPL) as published by the Free Software // Foundation, in version 2 as it comes in the "COPYING" file of the // VirtualBox OSE distribution. VirtualBox OSE is distributed in the // hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. // // CHANGELOG: // // 2019/06/08 // vector sigma // don't inject REV, RBr and EPCI keys if gSettings.REV is zeroed // #ifndef DEBUG_ALL #define DEBUG_DH 1 #else #define DEBUG_DH DEBUG_ALL #endif #if DEBUG_DH == 0 #define DBG(...) #else #define DBG(...) DebugLog(DEBUG_DH, __VA_ARGS__) #endif #include // Only use angled for Platform, else, xcode project won't compile #include "../include/OSTypes.h" #include "Nvram.h" #include "platformdata.h" #include "smbios.h" #include "cpu.h" #include "DataHubCpu.h" #include #define EFI_CPU_DATA_MAXIMUM_LENGTH 0x100 // gDataHub /// A pointer to the DataHubProtocol EFI_DATA_HUB_PROTOCOL *gDataHub; EFI_SUBCLASS_TYPE1_HEADER mCpuDataRecordHeader = { EFI_PROCESSOR_SUBCLASS_VERSION, // Version sizeof(EFI_SUBCLASS_TYPE1_HEADER), // Header Size 0, // Instance (initialize later) EFI_SUBCLASS_INSTANCE_NON_APPLICABLE, // SubInstance 0 // RecordType (initialize later) }; // gDataHubPlatformGuid /// The GUID of the DataHubProtocol EFI_GUID gDataHubPlatformGuid = { 0x64517cc8, 0x6561, 0x4051, { 0xb0, 0x3c, 0x59, 0x64, 0xb6, 0x0f, 0x4c, 0x7a } }; extern EFI_GUID gDataHubPlatformGuid; extern APPLE_SMC_IO_PROTOCOL *gAppleSmc; typedef union { EFI_CPU_DATA_RECORD *DataRecord; UINT8 *Raw; } EFI_CPU_DATA_RECORD_BUFFER; // PLATFORM_DATA /// The struct passed to "LogDataHub" holing key and value to be added #pragma pack(1) typedef struct { EFI_SUBCLASS_TYPE1_HEADER Hdr; /// 0x48 UINT32 NameLen; /// 0x58 (in bytes) UINT32 ValLen; /// 0x5c UINT8 Data[1]; /// 0x60 Name Value } PLATFORM_DATA_RECORD; #pragma pack() // CopyRecord /// Copy the data provided in arguments into a PLATFORM_DATA buffer /// /// @param Rec The buffer the data should be copied into /// @param Name The value for the member "name" /// @param Val The data the object should have /// @param ValLen The length of the parameter "Val" /// /// @return The size of the new PLATFORM_DATA object is returned UINT32 EFIAPI CopyRecord(IN PLATFORM_DATA_RECORD *Rec, IN CONST CHAR16 *Name, IN const void *Val, IN UINT32 ValLen) { CopyMem(&Rec->Hdr, &mCpuDataRecordHeader, sizeof(EFI_SUBCLASS_TYPE1_HEADER)); Rec->NameLen = (UINT32)StrLen(Name) * sizeof(CHAR16); Rec->ValLen = ValLen; CopyMem(Rec->Data, Name, Rec->NameLen); CopyMem(Rec->Data + Rec->NameLen, Val, ValLen); return (sizeof(EFI_SUBCLASS_TYPE1_HEADER) + 8 + Rec->NameLen + Rec->ValLen); } // LogDataHub /// Adds a key-value-pair to the DataHubProtocol EFI_STATUS EFIAPI LogDataHub(IN EFI_GUID *TypeGuid, IN CONST CHAR16 *Name, IN const void *Data, IN UINT32 DataSize) { UINT32 RecordSize; EFI_STATUS Status; PLATFORM_DATA_RECORD *platform_data_record; platform_data_record = (PLATFORM_DATA_RECORD*)AllocatePool(sizeof(PLATFORM_DATA_RECORD) + DataSize + EFI_CPU_DATA_MAXIMUM_LENGTH); if (platform_data_record == NULL) { return EFI_OUT_OF_RESOURCES; } RecordSize = CopyRecord(platform_data_record, Name, Data, DataSize); Status = gDataHub->LogData(gDataHub, TypeGuid, // DataRecordGuid &gDataHubPlatformGuid, // ProducerName (always) EFI_DATA_RECORD_CLASS_DATA, platform_data_record, RecordSize); FreePool(platform_data_record); return Status; } EFI_STATUS EFIAPI LogDataHubXString8(IN EFI_GUID *TypeGuid, IN CONST CHAR16 *Name, const XString8& s) { if ( s.sizeInBytesIncludingTerminator() > MAX_UINT32 ) panic("LogDataHub s.length > MAX_UINT32"); return LogDataHub(TypeGuid, Name, (void*)s.c_str(), (UINT32)s.sizeInBytesIncludingTerminator()); } EFI_STATUS EFIAPI LogDataHubXStringW(IN EFI_GUID *TypeGuid, IN CONST CHAR16 *Name, const XStringW& s) { if ( s.sizeInBytesIncludingTerminator() > MAX_UINT32 ) panic("LogDataHub s.length > MAX_UINT32"); return LogDataHub(TypeGuid, Name, (void*)s.wc_str(), (UINT32)s.sizeInBytesIncludingTerminator()); } // SetVariablesForOSX /** Installs our runtime services overrides. */ /** Original runtime services. */ EFI_RUNTIME_SERVICES gOrgRS; EFI_STATUS EFIAPI OvrSetVariable( IN CHAR16 *VariableName, IN EFI_GUID *VendorGuid, IN UINT32 Attributes, IN UINTN DataSize, IN void *Data ) { EFI_STATUS Status; UINTN i; for (i = 0; i < BlockRtVariableArray.size(); i++) { if (!CompareGuid(&BlockRtVariableArray[i].VarGuid, VendorGuid)) { continue; } if (BlockRtVariableArray[i].Name.isEmpty() || BlockRtVariableArray[i].Name[0] == L'*' || BlockRtVariableArray[i].Name == LStringW(VariableName) ) { return EFI_SUCCESS; } } Status = gOrgRS.SetVariable(VariableName, VendorGuid, Attributes, DataSize, Data); return Status; } EFI_STATUS EFIAPI OvrRuntimeServices(EFI_RUNTIME_SERVICES *RS) { EFI_STATUS Status; CopyMem(&gOrgRS, RS, sizeof(EFI_RUNTIME_SERVICES)); RS->SetVariable = (EFI_SET_VARIABLE)OvrSetVariable; RS->Hdr.CRC32 = 0; Status = gBS->CalculateCrc32(RS, RS->Hdr.HeaderSize, &RS->Hdr.CRC32); return Status; } /// Sets the volatile and non-volatile variables used by OS X EFI_STATUS EFIAPI SetVariablesForOSX(LOADER_ENTRY *Entry) { // The variable names used should be made global constants to prevent them being allocated multiple times UINT32 Attributes; UINT32 Color; CONST CHAR8 *None; CONST CHAR8 *NvidiaWebValue; CONST CHAR16 *KbdPrevLang; UINTN LangLen; void *OldData; // UINT64 os_version = AsciiOSVersionToUint64(Entry->OSVersion); CHAR8 *PlatformLang; EFI_GUID uuid; gSettings.getUUID(&uuid); // // firmware Variables // if (BlockRtVariableArray.size() > 0) { OvrRuntimeServices(gRT); } // As found on a real Mac, the system-id variable solely has the BS flag SetNvramVariable(L"system-id", &gEfiAppleNvramGuid, EFI_VARIABLE_BOOTSERVICE_ACCESS, sizeof(uuid), &uuid); Attributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS; if (gSettings.RtMLB.notEmpty()) { if ( gSettings.RtMLB.length() != 17 ) { DBG("** Warning: Your MLB is not suitable for iMessage(must be 17 chars long) !\n"); } SetNvramXString8(L"MLB", &gEfiAppleNvramGuid, Attributes, gSettings.RtMLB); } if (gSettings.RtROM.notEmpty()) { SetNvramVariable(L"ROM", &gEfiAppleNvramGuid, Attributes, gSettings.RtROM.size(), gSettings.RtROM.vdata()); } SetNvramVariable(L"FirmwareFeatures", &gEfiAppleNvramGuid, Attributes, sizeof(gFwFeatures), &gFwFeatures); // Download-Fritz: Should be added to SMBIOS or at least to some other config section AddNvramVariable(L"FirmwareFeaturesMask", &gEfiAppleNvramGuid, Attributes, sizeof(gFwFeaturesMask), &gFwFeaturesMask); // HW_MLB and HW_ROM are also around on some Macs with the same values as MLB and ROM AddNvramXString8(L"HW_BID", &gEfiAppleNvramGuid, Attributes, gSettings.BoardNumber); // // OS X non-volatile Variables // // note: some gEfiAppleBootGuid vars present in nvram.plist are already set by PutNvramPlistToRtVars() // we should think how to handle those vars from nvram.plist and ones set here from gSettings if ((gFirmwareClover && gDriversFlags.EmuVariableLoaded) || gSettings.KbdPrevLang) { // using AddNvramVariable content instead of calling the function to do LangLen calculation only when necessary // Do not mess with prev-lang:kbd on UEFI systems without NVRAM emulation; it's OS X's business KbdPrevLang = L"prev-lang:kbd"; OldData = (__typeof__(OldData))GetNvramVariable(KbdPrevLang, &gEfiAppleBootGuid, NULL, NULL); if (OldData == NULL) { gSettings.Language.trim(); SetNvramXString8(KbdPrevLang, &gEfiAppleBootGuid, Attributes, gSettings.Language); } else { FreePool(OldData); } } else { Attributes |= EFI_VARIABLE_NON_VOLATILE; } //#define EFI_PLATFORM_LANG_VARIABLE_NAME L"PlatformLang" PlatformLang = (__typeof__(PlatformLang))GetNvramVariable(EFI_PLATFORM_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, NULL, NULL); // // On some platforms with missing gEfiUnicodeCollation2ProtocolGuid EFI_PLATFORM_LANG_VARIABLE_NAME is set // to the value different from "en-...". This is not going to work with our driver UEFI Shell load failures. // We did not overwrite EFI_PLATFORM_LANG_VARIABLE_NAME, but it uses some other language. // // if (!PlatformLang || AsciiStrnCmp (PlatformLang, "en-", 3)) { if (!PlatformLang) { SetNvramVariable(EFI_PLATFORM_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, Attributes, 6, "en-US"); } if (PlatformLang) { FreePool(PlatformLang); } None = "none"; AddNvramVariable(L"security-mode", &gEfiAppleBootGuid, Attributes, 5, (void*)None); // we should have two UUID: platform and system // NO! Only Platform is the best solution if (!gSettings.ShouldInjectSystemID()) { if (gSettings.SmUUID.notEmpty()) { SetNvramVariable(L"platform-uuid", &gEfiAppleBootGuid, Attributes, sizeof(uuid), &uuid); } else { AddNvramVariable(L"platform-uuid", &gEfiAppleBootGuid, Attributes, sizeof(uuid), &uuid); } } // Download-Fritz: Do not mess with BacklightLevel; it's OS X's business if (gMobile) { if (gSettings.BacklightLevelConfig) { SetNvramVariable(L"backlight-level", &gEfiAppleBootGuid, Attributes, sizeof(gSettings.BacklightLevel), &gSettings.BacklightLevel); } else { AddNvramVariable(L"backlight-level", &gEfiAppleBootGuid, Attributes, sizeof(gSettings.BacklightLevel), &gSettings.BacklightLevel); } } if (gSettings.DefaultBackgroundColor == 0x80000000) { DeleteNvramVariable(L"DefaultBackgroundColor", &gEfiAppleNvramGuid); } else { UINT16 ActualDensity = 0xE1; UINT16 DensityThreshold = 0x96; UINT64 ConfigStatus = 0; Color = gSettings.DefaultBackgroundColor; DBG("set DefaultBackgroundColor=0x%x\n", Color); SetNvramVariable(L"DefaultBackgroundColor", &gEfiAppleNvramGuid, Attributes, 4, &Color); // add some UI variables SetNvramVariable(L"ActualDensity", &gEfiAppleBootGuid, Attributes, 2, &ActualDensity); SetNvramVariable(L"DensityThreshold", &gEfiAppleBootGuid, Attributes, 2, &DensityThreshold); SetNvramVariable(L"gfx-saved-config-restore-status", &gEfiAppleNvramGuid, Attributes, 8, &ConfigStatus); } if (gSettings.UIScale == 0x80000000) { DeleteNvramVariable(L"UIScale", &gEfiAppleNvramGuid); } else { SetNvramVariable(L"UIScale", &gEfiAppleNvramGuid, Attributes, 1, &gSettings.UIScale); } if (gSettings.EFILoginHiDPI == 0x80000000) { DeleteNvramVariable(L"EFILoginHiDPI", &gEfiAppleBootGuid); } else { SetNvramVariable(L"EFILoginHiDPI", &gEfiAppleBootGuid, Attributes, 4, &gSettings.EFILoginHiDPI); } // ->GetVariable(flagstate, gEfiAppleBootGuid, 0/0, 20, 10FE110) = Not Found if (gSettings.flagstate[3] == 0x80) { DeleteNvramVariable(L"flagstate", &gEfiAppleBootGuid); } else { SetNvramVariable(L"flagstate", &gEfiAppleBootGuid, Attributes, 32, &gSettings.flagstate); } // Hack for recovery by Asgorath if (gSettings.CsrActiveConfig != 0xFFFF) { SetNvramVariable(L"csr-active-config", &gEfiAppleBootGuid, Attributes, sizeof(gSettings.CsrActiveConfig), &gSettings.CsrActiveConfig); } /* if (gSettings.BooterConfig != 0) { SetNvramVariable(L"bootercfg", &gEfiAppleBootGuid, Attributes, sizeof(gSettings.BooterConfig), &gSettings.BooterConfig); } */ if ( gSettings.BooterCfgStr.notEmpty() ) { SetNvramXString8(L"bootercfg", &gEfiAppleBootGuid, Attributes, gSettings.BooterCfgStr); } else { DeleteNvramVariable(L"bootercfg", &gEfiAppleBootGuid); } if (gSettings.NvidiaWeb) { NvidiaWebValue = "1"; SetNvramVariable(L"nvda_drv", &gEfiAppleBootGuid, Attributes, 2, (void*)NvidiaWebValue); } else { DeleteNvramVariable(L"nvda_drv", &gEfiAppleBootGuid); } if (!gDriversFlags.AptioMemFixLoaded) { DeleteNvramVariable(L"recovery-boot-mode", &gEfiAppleBootGuid); } // Check for AptioFix2Drv loaded to store efi-boot-device for special boot if (gDriversFlags.AptioFix2Loaded || gDriversFlags.AptioFixLoaded || gDriversFlags.AptioFix3Loaded || gDriversFlags.AptioMemFixLoaded) { EFI_STATUS Status; REFIT_VOLUME *Volume = Entry->Volume; const EFI_DEVICE_PATH_PROTOCOL *DevicePath = Volume->DevicePath; // We need to remember from which device we boot, to make silence boot while special recovery boot Status = gRT->SetVariable(L"specialbootdevice", &gEfiAppleBootGuid, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, GetDevicePathSize(DevicePath), (UINT8 *)DevicePath); if (EFI_ERROR(Status)) { DBG("can't set specialbootdevice!\n"); } } // Sherlocks: to fix "OSInstall.mpkg appears to be missing or damaged" in 10.13+, we should remove this variables. if (Entry->LoaderType == OSTYPE_OSX_INSTALLER) { if (Entry->macOSVersion.isEmpty() || Entry->macOSVersion > MacOsVersion("10.12"_XS8)) { DeleteNvramVariable(L"install-product-url", &gEfiAppleBootGuid); DeleteNvramVariable(L"previous-system-uuid", &gEfiAppleBootGuid); } } //one more variable can be set for 10.15.4 //sudo nvram wake-failure=%00%00%00%00%00 LangLen = 0; AddNvramVariable(L"wake-failure", &gEfiAppleBootGuid, Attributes, 5, &LangLen); return EFI_SUCCESS; } void AddSMCkey(SMC_KEY Key, SMC_DATA_SIZE Size, SMC_KEY_TYPE Type, SMC_DATA *Data) { if (gAppleSmc && (gAppleSmc->Signature == NON_APPLE_SMC_SIGNATURE)) { gAppleSmc->SmcAddKey(gAppleSmc, Key, Size, Type, 0xC0); gAppleSmc->SmcWriteValue(gAppleSmc, Key, Size, Data); } } // SetupDataForOSX /// Sets the DataHub data used by OS X void EFIAPI SetupDataForOSX(BOOLEAN Hibernate) { EFI_STATUS Status; UINT32 DevPathSupportedVal; UINT64 FrontSideBus; UINT64 CpuSpeed; UINT64 TscFrequency; UINT64 ARTFrequency; UINTN Revision; UINT16 Zero = 0; BOOLEAN isRevLess = (gSettings.REV[0] == 0 && gSettings.REV[1] == 0 && gSettings.REV[2] == 0 && gSettings.REV[3] == 0 && gSettings.REV[4] == 0 && gSettings.REV[5] == 0); Revision = StrDecimalToUintn(gFirmwareRevision); // fool proof FrontSideBus = gCPUStructure.FSBFrequency; if ((FrontSideBus < (50 * Mega)) || (FrontSideBus > (1000 * Mega))) { DBG("Wrong FrontSideBus=%llu, set to 100MHz\n", FrontSideBus); FrontSideBus = 100 * Mega; } if (gSettings.QEMU) { FrontSideBus = gCPUStructure.TSCFrequency; switch (gCPUStructure.Model) { case CPU_MODEL_DOTHAN: case CPU_MODEL_YONAH: case CPU_MODEL_MEROM: case CPU_MODEL_PENRYN: FrontSideBus = DivU64x32(FrontSideBus, 4); break; default: break; } DBG("Using QEMU FrontSideBus=%llull\n", FrontSideBus); } // Save values into gSettings for the genconfig aim gSettings.BusSpeed = (UINT32)DivU64x32(FrontSideBus, Kilo); CpuSpeed = gCPUStructure.CPUFrequency; gSettings.CpuFreqMHz = (UINT32)DivU64x32(CpuSpeed, Mega); // Locate DataHub Protocol Status = gBS->LocateProtocol(&gEfiDataHubProtocolGuid, NULL, (void**)&gDataHub); if (!EFI_ERROR(Status)) { XStringW ProductName; ProductName.takeValueFrom(gSettings.ProductName); XStringW SerialNumber; SerialNumber.takeValueFrom(gSettings.SerialNr); LogDataHub(&gEfiProcessorSubClassGuid, L"FSBFrequency", &FrontSideBus, sizeof(UINT64)); if (gCPUStructure.ARTFrequency && gSettings.UseARTFreq) { ARTFrequency = gCPUStructure.ARTFrequency; LogDataHub(&gEfiProcessorSubClassGuid, L"ARTFrequency", &ARTFrequency, sizeof(UINT64)); } TscFrequency = 0; //gCPUStructure.TSCFrequency; LogDataHub(&gEfiProcessorSubClassGuid, L"InitialTSC", &TscFrequency, sizeof(UINT64)); LogDataHub(&gEfiProcessorSubClassGuid, L"CPUFrequency", &CpuSpeed, sizeof(UINT64)); //gSettings.BoardNumber LogDataHubXString8(&gEfiMiscSubClassGuid, L"board-id", gSettings.BoardNumber); TscFrequency++; LogDataHub(&gEfiProcessorSubClassGuid, L"board-rev", &TscFrequency, 1); DevPathSupportedVal = 1; LogDataHub(&gEfiMiscSubClassGuid, L"DevicePathsSupported", &DevPathSupportedVal, sizeof(UINT32)); LogDataHubXStringW(&gEfiMiscSubClassGuid, L"Model", ProductName); LogDataHubXStringW(&gEfiMiscSubClassGuid, L"SystemSerialNumber", SerialNumber); if (gSettings.ShouldInjectSystemID()) { EFI_GUID uuid; gSettings.getUUID(&uuid); LogDataHub(&gEfiMiscSubClassGuid, L"system-id", &uuid, sizeof(uuid)); } LogDataHub(&gEfiProcessorSubClassGuid, L"clovergui-revision", &Revision, sizeof(UINT32)); // collect info about real hardware LogDataHubXString8(&gEfiMiscSubClassGuid, L"OEMVendor", gSettings.OEMVendor); LogDataHubXString8(&gEfiMiscSubClassGuid, L"OEMProduct", gSettings.OEMProduct); LogDataHubXString8(&gEfiMiscSubClassGuid, L"OEMBoard", gSettings.OEMBoard); // SMC helper if (!isRevLess) { LogDataHub(&gEfiMiscSubClassGuid, L"RBr", &gSettings.RBr, 8); LogDataHub(&gEfiMiscSubClassGuid, L"EPCI", &gSettings.EPCI, 4); LogDataHub(&gEfiMiscSubClassGuid, L"REV", &gSettings.REV, 6); } LogDataHub(&gEfiMiscSubClassGuid, L"RPlt", &gSettings.RPlt, 8); LogDataHub(&gEfiMiscSubClassGuid, L"BEMB", &gSettings.Mobile, 1); // all current settings XBuffer xb = gSettings.serialize(); LogDataHub(&gEfiMiscSubClassGuid, L"Settings", xb.data(), (UINT32)xb.size()); }else{ MsgLog("DataHub protocol not located. Smbios not send to datahub\n"); } if (!gAppleSmc) { return; } if (!isRevLess) { AddSMCkey(SMC_MAKE_KEY('R','B','r',' '), 8, SmcKeyTypeCh8, (SMC_DATA *)&gSettings.RBr); AddSMCkey(SMC_MAKE_KEY('E','P','C','I'), 4, SmcKeyTypeUint32, (SMC_DATA *)&gSettings.EPCI); AddSMCkey(SMC_MAKE_KEY('R','E','V',' '), 6, SmcKeyTypeCh8, (SMC_DATA *)&gSettings.REV); } AddSMCkey(SMC_MAKE_KEY('R','P','l','t'), 8, SmcKeyTypeCh8, (SMC_DATA *)&gSettings.RPlt); AddSMCkey(SMC_MAKE_KEY('B','E','M','B'), 1, SmcKeyTypeFlag, (SMC_DATA *)&gSettings.Mobile); //laptop battery keys will be better to import from nvram.plist or read from ACPI(?) //they are needed for FileVault2 who want to draw battery status AddSMCkey(SMC_MAKE_KEY('B','A','T','P'), 1, SmcKeyTypeFlag, (SMC_DATA *)&Zero); //isBatteryPowered AddSMCkey(SMC_MAKE_KEY('B','N','u','m'), 1, SmcKeyTypeUint8, (SMC_DATA *)&gSettings.Mobile); // Num Batteries if (gSettings.Mobile) { AddSMCkey(SMC_MAKE_KEY('B','B','I','N'), 1, SmcKeyTypeUint8, (SMC_DATA *)&gSettings.Mobile); //Battery inserted } AddSMCkey(SMC_MAKE_KEY('M','S','T','c'), 1, SmcKeyTypeUint8, (SMC_DATA *)&Zero); // CPU Plimit AddSMCkey(SMC_MAKE_KEY('M','S','A','c'), 2, SmcKeyTypeUint16, (SMC_DATA *)&Zero);// GPU Plimit // AddSMCkey(SMC_MAKE_KEY('M','S','L','D'), 1, SmcKeyTypeUint8, (SMC_DATA *)&Zero); //isLidClosed Zero = Hibernate?((ResumeFromCoreStorage||gSettings.Boot.HibernationFixup)?25:29):0; AddSMCkey(SMC_MAKE_KEY('M','S','W','r'), 1, SmcKeyTypeUint8, (SMC_DATA *)&Zero); Zero = 1; AddSMCkey(SMC_MAKE_KEY('M','S','F','W'), 2, SmcKeyTypeUint8, (SMC_DATA *)&Zero); Zero = 0x300; AddSMCkey(SMC_MAKE_KEY('M','S','P','S'), 2, SmcKeyTypeUint16, (SMC_DATA *)&Zero); }