diff options
Diffstat (limited to 'src/VBox/Devices/EFI/VBoxSmcUtil-darwin.cpp')
-rw-r--r-- | src/VBox/Devices/EFI/VBoxSmcUtil-darwin.cpp | 356 |
1 files changed, 356 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/VBoxSmcUtil-darwin.cpp b/src/VBox/Devices/EFI/VBoxSmcUtil-darwin.cpp new file mode 100644 index 00000000..73ff5cea --- /dev/null +++ b/src/VBox/Devices/EFI/VBoxSmcUtil-darwin.cpp @@ -0,0 +1,356 @@ +/* $Id: VBoxSmcUtil-darwin.cpp $ */ +/** @file + * VBoxSmcUtil - Quick hack for viewing SMC data on a mac. + */ + +/* + * Copyright (C) 2013-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <iprt/asm.h> +#include <iprt/err.h> +#include <iprt/ctype.h> +#include <iprt/initterm.h> +#include <iprt/message.h> +#include <iprt/stream.h> +#include <iprt/string.h> + +#include <mach/mach.h> +#include <IOKit/IOKitLib.h> +#include <IOKit/IOReturn.h> +#include <CoreFoundation/CoreFoundation.h> +#include <unistd.h> + + +/********************************************************************************************************************************* +* Structures and Typedefs * +*********************************************************************************************************************************/ +enum +{ + kSMCSuccess = 0, + kSMCError = 1 +}; + +typedef enum +{ + kSMCUserClientOpen = 0, + kSMCUserClientClose, + kSMCHandleYPCEvent, + + kSMCPlaceholder1, + kSMCNumberOfMethods, + + kSMCReadKey, + kSMCWriteKey, + kSMCGetKeyCount, + kSMCGetKeyFromIndex, + kSMCGetKeyInfo, + + kSMCFireInterrupt, + kSMCGetPLimits, + kSMCGetVers, + + kSMCPlaceholder2, + + kSMCReadStatus, + kSMCReadResult, + kSMCVariableCommand +} KSMCFUNCTION; + +typedef struct +{ + RTUINT32U uKey; + struct + { + uint8_t uMajor; + uint8_t uMinor; + uint8_t uBuild; + uint8_t uReserved; + uint16_t uRelease; + } Version; + struct + { + uint16_t uVer; + uint16_t cb; + uint32_t uCpuPLimit; + uint32_t uGpuPLimit; + uint32_t uMemPLimit; + } SMCPLimitData; + + struct + { + IOByteCount cbData; + RTUINT32U uDataType; + uint8_t fAttr; + } KeyInfo; + + uint8_t uResult; + uint8_t fStatus; + uint8_t bData; + uint32_t u32Data; + uint8_t abValue[32]; +} SMCPARAM; + + +/********************************************************************************************************************************* +* Global Variables * +*********************************************************************************************************************************/ +io_service_t g_hSmcService = IO_OBJECT_NULL; +io_connect_t g_hSmcConnect = IO_OBJECT_NULL; + + +static int ConnectToSmc(void) +{ + g_hSmcService = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("AppleSMC")); + if (g_hSmcService == IO_OBJECT_NULL) + return VERR_NOT_FOUND; + + IOReturn rcIo = IOServiceOpen(g_hSmcService, mach_task_self(), 1, &g_hSmcConnect); + if (rcIo == kIOReturnSuccess && g_hSmcConnect != IO_OBJECT_NULL) + { + rcIo = IOConnectCallMethod(g_hSmcConnect, kSMCUserClientOpen, NULL, 0, NULL, 0, NULL, NULL, NULL, NULL); + if (rcIo == kIOReturnSuccess) + return VINF_SUCCESS; + RTMsgError("kSMCUserClientOpen failed: %#x (%#x)\n", rcIo, rcIo); + } + else + { + RTMsgError("IOServiceOpen failed: %#x (%#x)\n", rcIo, rcIo); + g_hSmcConnect = IO_OBJECT_NULL; + } + return RTErrConvertFromDarwinIO(rcIo); +} + + +static void DisconnectFromSmc(void) +{ + if (g_hSmcConnect) + { + IOConnectCallMethod(g_hSmcConnect, kSMCUserClientClose, NULL, 0, NULL, 0, NULL, NULL, NULL, NULL); + IOServiceClose(g_hSmcConnect); + g_hSmcConnect = IO_OBJECT_NULL; + } + + if (g_hSmcService) + { + IOServiceClose(g_hSmcService); + g_hSmcService = IO_OBJECT_NULL; + } +} + +static int CallSmc(KSMCFUNCTION enmFunction, SMCPARAM *pIn, SMCPARAM *pOut) +{ + RT_ZERO(*pOut); + pIn->bData = enmFunction; + size_t cbOut = sizeof(*pOut); + IOReturn rcIo = IOConnectCallStructMethod(g_hSmcConnect, kSMCHandleYPCEvent, pIn, sizeof(*pIn), pOut, &cbOut); + if (rcIo == kIOReturnSuccess) + return VINF_SUCCESS; + RTMsgError("SMC call %d failed: rcIo=%d (%#x)\n", enmFunction, rcIo, rcIo); + return RTErrConvertFromDarwinIO(rcIo); +} + +static int GetKeyCount(uint32_t *pcKeys) +{ + SMCPARAM In; + SMCPARAM Out; + RT_ZERO(In); RT_ZERO(Out); + In.KeyInfo.cbData = sizeof(uint32_t); + int rc = CallSmc(kSMCGetKeyCount, &In, &Out); + if (RT_SUCCESS(rc)) + *pcKeys = RT_BE2H_U32(Out.u32Data); + else + *pcKeys = 1; + return rc; +} + +static int GetKeyByIndex(uint32_t iKey, SMCPARAM *pKeyData) +{ + SMCPARAM In; + RT_ZERO(In); + In.u32Data = iKey; + int rc = CallSmc(kSMCGetKeyFromIndex, &In, pKeyData); + if (RT_SUCCESS(rc)) + { + if (pKeyData->uResult == kSMCSuccess) + { + SMCPARAM Tmp = *pKeyData; + + /* Get the key info. */ + RT_ZERO(In); + In.uKey.u = Tmp.uKey.u; + rc = CallSmc(kSMCGetKeyInfo, &In, pKeyData); + if (RT_SUCCESS(rc) && pKeyData->uResult == kSMCSuccess) + { + Tmp.KeyInfo = pKeyData->KeyInfo; + + /* Get the key value. */ + RT_ZERO(In); + In.uKey = Tmp.uKey; + In.KeyInfo = Tmp.KeyInfo; + rc = CallSmc(kSMCReadKey, &In, pKeyData); + if (RT_SUCCESS(rc) && (pKeyData->uResult == kSMCSuccess || pKeyData->uResult == 0x85 /* not readable */)) + { + pKeyData->uKey = Tmp.uKey; + pKeyData->KeyInfo = Tmp.KeyInfo; + rc = VINF_SUCCESS; + } + else if (RT_SUCCESS(rc)) + { + RTMsgError("kSMCReadKey failed on #%x/%.4s: %#x\n", iKey, Tmp.uKey.au8, pKeyData->uResult); + rc = VERR_IO_GEN_FAILURE; + } + } + else if (RT_SUCCESS(rc)) + { + RTMsgError("kSMCGetKeyInfo failed on #%x/%.4s: %#x\n", iKey, Tmp.uKey.au8, pKeyData->uResult); + rc = VERR_IO_GEN_FAILURE; + } + } + else + { + RTMsgError("kSMCGetKeyFromIndex failed on #%x: %#x\n", iKey, pKeyData->uResult); + rc = VERR_IO_GEN_FAILURE; + } + } + return rc; +} + + +static int GetKeyByName(uint32_t uKey, SMCPARAM *pKeyData) +{ + SMCPARAM In; + RT_ZERO(In); + In.uKey.u = uKey; + int rc = CallSmc(kSMCGetKeyInfo, &In, pKeyData); + if (RT_SUCCESS(rc) && pKeyData->uResult == kSMCSuccess) + { + SMCPARAM Tmp = *pKeyData; + + /* Get the key value. */ + RT_ZERO(In); + In.uKey.u = uKey; + In.KeyInfo = Tmp.KeyInfo; + rc = CallSmc(kSMCReadKey, &In, pKeyData); + if (RT_SUCCESS(rc) && (pKeyData->uResult == kSMCSuccess || pKeyData->uResult == 0x85 /* not readable */)) + { + pKeyData->uKey.u = uKey; + pKeyData->KeyInfo = Tmp.KeyInfo; + rc = VINF_SUCCESS; + } + else if (RT_SUCCESS(rc)) + { + RTMsgError("kSMCReadKey failed on %.4s: %#x\n", &uKey, pKeyData->uResult); + rc = VERR_IO_GEN_FAILURE; + } + } + else if (RT_SUCCESS(rc)) + { + RTMsgError("kSMCGetKeyInfo failed on %.4s: %#x\n", &uKey, pKeyData->uResult); + rc = VERR_IO_GEN_FAILURE; + } + return rc; +} + +static void DisplayKey(SMCPARAM *pKey) +{ + pKey->uKey.u = RT_BE2H_U32(pKey->uKey.u); + pKey->KeyInfo.uDataType.u = RT_BE2H_U32(pKey->KeyInfo.uDataType.u); + RTPrintf("key=%4.4s type=%4.4s cb=%#04x fAttr=%#04x", + pKey->uKey.au8, pKey->KeyInfo.uDataType.au8, pKey->KeyInfo.cbData, pKey->KeyInfo.fAttr); + if (pKey->uResult == kSMCSuccess) + { + bool fPrintable = true; + for (uint32_t off = 0; off < pKey->KeyInfo.cbData; off++) + if (!RT_C_IS_PRINT(pKey->abValue[off])) + { + fPrintable = false; + break; + } + if (fPrintable) + RTPrintf(" %.*s\n", pKey->KeyInfo.cbData, pKey->abValue); + else + RTPrintf(" %.*Rhxs\n", pKey->KeyInfo.cbData, pKey->abValue); + } + else if (pKey->uResult == 0x85) + RTPrintf(" <not readable>\n"); +} + +static void DisplayKeyByName(uint32_t uKey) +{ + SMCPARAM Key; + int rc = GetKeyByName(uKey, &Key); + if (RT_SUCCESS(rc)) + DisplayKey(&Key); +} + + +int main(int argc, char **argv) +{ + int rc = RTR3InitExe(argc, &argv, 0); + if (RT_FAILURE(rc)) + return RTMsgInitFailure(rc); + + rc = ConnectToSmc(); + if (RT_SUCCESS(rc)) + { + /* + * Dump the keys. + */ + uint32_t cKeys; + rc = GetKeyCount(&cKeys); + if (RT_SUCCESS(rc)) + RTPrintf("#Keys=%u\n", cKeys); + for (uint32_t iKey = 0; iKey < cKeys; iKey++) + { + SMCPARAM Key; + rc = GetKeyByIndex(iKey, &Key); + if (RT_SUCCESS(rc)) + { + RTPrintf("%#06x: ", iKey); + DisplayKey(&Key); + } + } + + /* + * Known keys that doesn't make it into the enumeration. + */ + DisplayKeyByName('OSK0'); + DisplayKeyByName('OSK1'); + DisplayKeyByName('OSK2'); + + /* Negative checks, sometimes maybe. */ + DisplayKeyByName('$Num'); + DisplayKeyByName('MSTf'); + DisplayKeyByName('MSDS'); + DisplayKeyByName('LSOF'); + } + DisconnectFromSmc(); + + if (RT_SUCCESS(rc)) + return RTEXITCODE_SUCCESS; + return RTEXITCODE_FAILURE; +} + |