VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/VBoxSmcUtil-darwin.cpp@ 106129

Last change on this file since 106129 was 106061, checked in by vboxsync, 2 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.8 KB
Line 
1/* $Id: VBoxSmcUtil-darwin.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * VBoxSmcUtil - Quick hack for viewing SMC data on a mac.
4 */
5
6/*
7 * Copyright (C) 2013-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#include <iprt/asm.h>
33#include <iprt/err.h>
34#include <iprt/ctype.h>
35#include <iprt/initterm.h>
36#include <iprt/message.h>
37#include <iprt/stream.h>
38#include <iprt/string.h>
39
40#include <mach/mach.h>
41#include <IOKit/IOKitLib.h>
42#include <IOKit/IOReturn.h>
43#include <CoreFoundation/CoreFoundation.h>
44#include <unistd.h>
45
46
47/*********************************************************************************************************************************
48* Structures and Typedefs *
49*********************************************************************************************************************************/
50enum
51{
52 kSMCSuccess = 0,
53 kSMCError = 1
54};
55
56typedef enum
57{
58 kSMCUserClientOpen = 0,
59 kSMCUserClientClose,
60 kSMCHandleYPCEvent,
61
62 kSMCPlaceholder1,
63 kSMCNumberOfMethods,
64
65 kSMCReadKey,
66 kSMCWriteKey,
67 kSMCGetKeyCount,
68 kSMCGetKeyFromIndex,
69 kSMCGetKeyInfo,
70
71 kSMCFireInterrupt,
72 kSMCGetPLimits,
73 kSMCGetVers,
74
75 kSMCPlaceholder2,
76
77 kSMCReadStatus,
78 kSMCReadResult,
79 kSMCVariableCommand
80} KSMCFUNCTION;
81
82typedef struct
83{
84 RTUINT32U uKey;
85 struct
86 {
87 uint8_t uMajor;
88 uint8_t uMinor;
89 uint8_t uBuild;
90 uint8_t uReserved;
91 uint16_t uRelease;
92 } Version;
93 struct
94 {
95 uint16_t uVer;
96 uint16_t cb;
97 uint32_t uCpuPLimit;
98 uint32_t uGpuPLimit;
99 uint32_t uMemPLimit;
100 } SMCPLimitData;
101
102 struct
103 {
104 IOByteCount cbData;
105 RTUINT32U uDataType;
106 uint8_t fAttr;
107 } KeyInfo;
108
109 uint8_t uResult;
110 uint8_t fStatus;
111 uint8_t bData;
112 uint32_t u32Data;
113 uint8_t abValue[32];
114} SMCPARAM;
115
116
117/*********************************************************************************************************************************
118* Global Variables *
119*********************************************************************************************************************************/
120io_service_t g_hSmcService = IO_OBJECT_NULL;
121io_connect_t g_hSmcConnect = IO_OBJECT_NULL;
122
123
124static int ConnectToSmc(void)
125{
126 RT_GCC_NO_WARN_DEPRECATED_BEGIN
127 g_hSmcService = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("AppleSMC")); /* kIOMasterPortDefault: Deprecated since 12.0. */
128 RT_GCC_NO_WARN_DEPRECATED_END
129 if (g_hSmcService == IO_OBJECT_NULL)
130 return VERR_NOT_FOUND;
131
132 IOReturn rcIo = IOServiceOpen(g_hSmcService, mach_task_self(), 1, &g_hSmcConnect);
133 if (rcIo == kIOReturnSuccess && g_hSmcConnect != IO_OBJECT_NULL)
134 {
135 rcIo = IOConnectCallMethod(g_hSmcConnect, kSMCUserClientOpen, NULL, 0, NULL, 0, NULL, NULL, NULL, NULL);
136 if (rcIo == kIOReturnSuccess)
137 return VINF_SUCCESS;
138 RTMsgError("kSMCUserClientOpen failed: %#x (%#x)\n", rcIo, rcIo);
139 }
140 else
141 {
142 RTMsgError("IOServiceOpen failed: %#x (%#x)\n", rcIo, rcIo);
143 g_hSmcConnect = IO_OBJECT_NULL;
144 }
145 return RTErrConvertFromDarwinIO(rcIo);
146}
147
148
149static void DisconnectFromSmc(void)
150{
151 if (g_hSmcConnect)
152 {
153 IOConnectCallMethod(g_hSmcConnect, kSMCUserClientClose, NULL, 0, NULL, 0, NULL, NULL, NULL, NULL);
154 IOServiceClose(g_hSmcConnect);
155 g_hSmcConnect = IO_OBJECT_NULL;
156 }
157
158 if (g_hSmcService)
159 {
160 IOServiceClose(g_hSmcService);
161 g_hSmcService = IO_OBJECT_NULL;
162 }
163}
164
165static int CallSmc(KSMCFUNCTION enmFunction, SMCPARAM *pIn, SMCPARAM *pOut)
166{
167 RT_ZERO(*pOut);
168 pIn->bData = enmFunction;
169 size_t cbOut = sizeof(*pOut);
170 IOReturn rcIo = IOConnectCallStructMethod(g_hSmcConnect, kSMCHandleYPCEvent, pIn, sizeof(*pIn), pOut, &cbOut);
171 if (rcIo == kIOReturnSuccess)
172 return VINF_SUCCESS;
173 RTMsgError("SMC call %d failed: rcIo=%d (%#x)\n", enmFunction, rcIo, rcIo);
174 return RTErrConvertFromDarwinIO(rcIo);
175}
176
177static int GetKeyCount(uint32_t *pcKeys)
178{
179 SMCPARAM In;
180 SMCPARAM Out;
181 RT_ZERO(In); RT_ZERO(Out);
182 In.KeyInfo.cbData = sizeof(uint32_t);
183 int rc = CallSmc(kSMCGetKeyCount, &In, &Out);
184 if (RT_SUCCESS(rc))
185 *pcKeys = RT_BE2H_U32(Out.u32Data);
186 else
187 *pcKeys = 1;
188 return rc;
189}
190
191static int GetKeyByIndex(uint32_t iKey, SMCPARAM *pKeyData)
192{
193 SMCPARAM In;
194 RT_ZERO(In);
195 In.u32Data = iKey;
196 int rc = CallSmc(kSMCGetKeyFromIndex, &In, pKeyData);
197 if (RT_SUCCESS(rc))
198 {
199 if (pKeyData->uResult == kSMCSuccess)
200 {
201 SMCPARAM Tmp = *pKeyData;
202
203 /* Get the key info. */
204 RT_ZERO(In);
205 In.uKey.u = Tmp.uKey.u;
206 rc = CallSmc(kSMCGetKeyInfo, &In, pKeyData);
207 if (RT_SUCCESS(rc) && pKeyData->uResult == kSMCSuccess)
208 {
209 Tmp.KeyInfo = pKeyData->KeyInfo;
210
211 /* Get the key value. */
212 RT_ZERO(In);
213 In.uKey = Tmp.uKey;
214 In.KeyInfo = Tmp.KeyInfo;
215 rc = CallSmc(kSMCReadKey, &In, pKeyData);
216 if (RT_SUCCESS(rc) && (pKeyData->uResult == kSMCSuccess || pKeyData->uResult == 0x85 /* not readable */))
217 {
218 pKeyData->uKey = Tmp.uKey;
219 pKeyData->KeyInfo = Tmp.KeyInfo;
220 rc = VINF_SUCCESS;
221 }
222 else if (RT_SUCCESS(rc))
223 {
224 RTMsgError("kSMCReadKey failed on #%x/%.4s: %#x\n", iKey, Tmp.uKey.au8, pKeyData->uResult);
225 rc = VERR_IO_GEN_FAILURE;
226 }
227 }
228 else if (RT_SUCCESS(rc))
229 {
230 RTMsgError("kSMCGetKeyInfo failed on #%x/%.4s: %#x\n", iKey, Tmp.uKey.au8, pKeyData->uResult);
231 rc = VERR_IO_GEN_FAILURE;
232 }
233 }
234 else
235 {
236 RTMsgError("kSMCGetKeyFromIndex failed on #%x: %#x\n", iKey, pKeyData->uResult);
237 rc = VERR_IO_GEN_FAILURE;
238 }
239 }
240 return rc;
241}
242
243
244static int GetKeyByName(uint32_t uKey, SMCPARAM *pKeyData)
245{
246 SMCPARAM In;
247 RT_ZERO(In);
248 In.uKey.u = uKey;
249 int rc = CallSmc(kSMCGetKeyInfo, &In, pKeyData);
250 if (RT_SUCCESS(rc) && pKeyData->uResult == kSMCSuccess)
251 {
252 SMCPARAM Tmp = *pKeyData;
253
254 /* Get the key value. */
255 RT_ZERO(In);
256 In.uKey.u = uKey;
257 In.KeyInfo = Tmp.KeyInfo;
258 rc = CallSmc(kSMCReadKey, &In, pKeyData);
259 if (RT_SUCCESS(rc) && (pKeyData->uResult == kSMCSuccess || pKeyData->uResult == 0x85 /* not readable */))
260 {
261 pKeyData->uKey.u = uKey;
262 pKeyData->KeyInfo = Tmp.KeyInfo;
263 rc = VINF_SUCCESS;
264 }
265 else if (RT_SUCCESS(rc))
266 {
267 RTMsgError("kSMCReadKey failed on %.4s: %#x\n", &uKey, pKeyData->uResult);
268 rc = VERR_IO_GEN_FAILURE;
269 }
270 }
271 else if (RT_SUCCESS(rc))
272 {
273 RTMsgError("kSMCGetKeyInfo failed on %.4s: %#x\n", &uKey, pKeyData->uResult);
274 rc = VERR_IO_GEN_FAILURE;
275 }
276 return rc;
277}
278
279static void DisplayKey(SMCPARAM *pKey)
280{
281 pKey->uKey.u = RT_BE2H_U32(pKey->uKey.u);
282 pKey->KeyInfo.uDataType.u = RT_BE2H_U32(pKey->KeyInfo.uDataType.u);
283 RTPrintf("key=%4.4s type=%4.4s cb=%#04x fAttr=%#04x",
284 pKey->uKey.au8, pKey->KeyInfo.uDataType.au8, pKey->KeyInfo.cbData, pKey->KeyInfo.fAttr);
285 if (pKey->uResult == kSMCSuccess)
286 {
287 bool fPrintable = true;
288 for (uint32_t off = 0; off < pKey->KeyInfo.cbData; off++)
289 if (!RT_C_IS_PRINT(pKey->abValue[off]))
290 {
291 fPrintable = false;
292 break;
293 }
294 if (fPrintable)
295 RTPrintf(" %.*s\n", pKey->KeyInfo.cbData, pKey->abValue);
296 else
297 RTPrintf(" %.*Rhxs\n", pKey->KeyInfo.cbData, pKey->abValue);
298 }
299 else if (pKey->uResult == 0x85)
300 RTPrintf(" <not readable>\n");
301}
302
303static void DisplayKeyByName(uint32_t uKey)
304{
305 SMCPARAM Key;
306 int rc = GetKeyByName(uKey, &Key);
307 if (RT_SUCCESS(rc))
308 DisplayKey(&Key);
309}
310
311
312int main(int argc, char **argv)
313{
314 int rc = RTR3InitExe(argc, &argv, 0);
315 if (RT_FAILURE(rc))
316 return RTMsgInitFailure(rc);
317
318 rc = ConnectToSmc();
319 if (RT_SUCCESS(rc))
320 {
321 /*
322 * Dump the keys.
323 */
324 uint32_t cKeys;
325 rc = GetKeyCount(&cKeys);
326 if (RT_SUCCESS(rc))
327 RTPrintf("#Keys=%u\n", cKeys);
328 for (uint32_t iKey = 0; iKey < cKeys; iKey++)
329 {
330 SMCPARAM Key;
331 rc = GetKeyByIndex(iKey, &Key);
332 if (RT_SUCCESS(rc))
333 {
334 RTPrintf("%#06x: ", iKey);
335 DisplayKey(&Key);
336 }
337 }
338
339 /*
340 * Known keys that doesn't make it into the enumeration.
341 */
342 DisplayKeyByName(RT_MAKE_U32_FROM_MSB_U8('O','S','K','0'));
343 DisplayKeyByName(RT_MAKE_U32_FROM_MSB_U8('O','S','K','1'));
344 DisplayKeyByName(RT_MAKE_U32_FROM_MSB_U8('O','S','K','2'));
345
346 /* Negative checks, sometimes maybe. */
347 DisplayKeyByName(RT_MAKE_U32_FROM_MSB_U8('$','N','u','m'));
348 DisplayKeyByName(RT_MAKE_U32_FROM_MSB_U8('M','S','T','f'));
349 DisplayKeyByName(RT_MAKE_U32_FROM_MSB_U8('M','S','D','S'));
350 DisplayKeyByName(RT_MAKE_U32_FROM_MSB_U8('L','S','O','F'));
351 }
352 DisconnectFromSmc();
353
354 if (RT_SUCCESS(rc))
355 return RTEXITCODE_SUCCESS;
356 return RTEXITCODE_FAILURE;
357}
358
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette