VirtualBox

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

Last change on this file since 99286 was 98103, checked in by vboxsync, 2 years 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.5 KB
Line 
1/* $Id: VBoxSmcUtil-darwin.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * VBoxSmcUtil - Quick hack for viewing SMC data on a mac.
4 */
5
6/*
7 * Copyright (C) 2013-2023 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 g_hSmcService = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("AppleSMC"));
127 if (g_hSmcService == IO_OBJECT_NULL)
128 return VERR_NOT_FOUND;
129
130 IOReturn rcIo = IOServiceOpen(g_hSmcService, mach_task_self(), 1, &g_hSmcConnect);
131 if (rcIo == kIOReturnSuccess && g_hSmcConnect != IO_OBJECT_NULL)
132 {
133 rcIo = IOConnectCallMethod(g_hSmcConnect, kSMCUserClientOpen, NULL, 0, NULL, 0, NULL, NULL, NULL, NULL);
134 if (rcIo == kIOReturnSuccess)
135 return VINF_SUCCESS;
136 RTMsgError("kSMCUserClientOpen failed: %#x (%#x)\n", rcIo, rcIo);
137 }
138 else
139 {
140 RTMsgError("IOServiceOpen failed: %#x (%#x)\n", rcIo, rcIo);
141 g_hSmcConnect = IO_OBJECT_NULL;
142 }
143 return RTErrConvertFromDarwinIO(rcIo);
144}
145
146
147static void DisconnectFromSmc(void)
148{
149 if (g_hSmcConnect)
150 {
151 IOConnectCallMethod(g_hSmcConnect, kSMCUserClientClose, NULL, 0, NULL, 0, NULL, NULL, NULL, NULL);
152 IOServiceClose(g_hSmcConnect);
153 g_hSmcConnect = IO_OBJECT_NULL;
154 }
155
156 if (g_hSmcService)
157 {
158 IOServiceClose(g_hSmcService);
159 g_hSmcService = IO_OBJECT_NULL;
160 }
161}
162
163static int CallSmc(KSMCFUNCTION enmFunction, SMCPARAM *pIn, SMCPARAM *pOut)
164{
165 RT_ZERO(*pOut);
166 pIn->bData = enmFunction;
167 size_t cbOut = sizeof(*pOut);
168 IOReturn rcIo = IOConnectCallStructMethod(g_hSmcConnect, kSMCHandleYPCEvent, pIn, sizeof(*pIn), pOut, &cbOut);
169 if (rcIo == kIOReturnSuccess)
170 return VINF_SUCCESS;
171 RTMsgError("SMC call %d failed: rcIo=%d (%#x)\n", enmFunction, rcIo, rcIo);
172 return RTErrConvertFromDarwinIO(rcIo);
173}
174
175static int GetKeyCount(uint32_t *pcKeys)
176{
177 SMCPARAM In;
178 SMCPARAM Out;
179 RT_ZERO(In); RT_ZERO(Out);
180 In.KeyInfo.cbData = sizeof(uint32_t);
181 int rc = CallSmc(kSMCGetKeyCount, &In, &Out);
182 if (RT_SUCCESS(rc))
183 *pcKeys = RT_BE2H_U32(Out.u32Data);
184 else
185 *pcKeys = 1;
186 return rc;
187}
188
189static int GetKeyByIndex(uint32_t iKey, SMCPARAM *pKeyData)
190{
191 SMCPARAM In;
192 RT_ZERO(In);
193 In.u32Data = iKey;
194 int rc = CallSmc(kSMCGetKeyFromIndex, &In, pKeyData);
195 if (RT_SUCCESS(rc))
196 {
197 if (pKeyData->uResult == kSMCSuccess)
198 {
199 SMCPARAM Tmp = *pKeyData;
200
201 /* Get the key info. */
202 RT_ZERO(In);
203 In.uKey.u = Tmp.uKey.u;
204 rc = CallSmc(kSMCGetKeyInfo, &In, pKeyData);
205 if (RT_SUCCESS(rc) && pKeyData->uResult == kSMCSuccess)
206 {
207 Tmp.KeyInfo = pKeyData->KeyInfo;
208
209 /* Get the key value. */
210 RT_ZERO(In);
211 In.uKey = Tmp.uKey;
212 In.KeyInfo = Tmp.KeyInfo;
213 rc = CallSmc(kSMCReadKey, &In, pKeyData);
214 if (RT_SUCCESS(rc) && (pKeyData->uResult == kSMCSuccess || pKeyData->uResult == 0x85 /* not readable */))
215 {
216 pKeyData->uKey = Tmp.uKey;
217 pKeyData->KeyInfo = Tmp.KeyInfo;
218 rc = VINF_SUCCESS;
219 }
220 else if (RT_SUCCESS(rc))
221 {
222 RTMsgError("kSMCReadKey failed on #%x/%.4s: %#x\n", iKey, Tmp.uKey.au8, pKeyData->uResult);
223 rc = VERR_IO_GEN_FAILURE;
224 }
225 }
226 else if (RT_SUCCESS(rc))
227 {
228 RTMsgError("kSMCGetKeyInfo failed on #%x/%.4s: %#x\n", iKey, Tmp.uKey.au8, pKeyData->uResult);
229 rc = VERR_IO_GEN_FAILURE;
230 }
231 }
232 else
233 {
234 RTMsgError("kSMCGetKeyFromIndex failed on #%x: %#x\n", iKey, pKeyData->uResult);
235 rc = VERR_IO_GEN_FAILURE;
236 }
237 }
238 return rc;
239}
240
241
242static int GetKeyByName(uint32_t uKey, SMCPARAM *pKeyData)
243{
244 SMCPARAM In;
245 RT_ZERO(In);
246 In.uKey.u = uKey;
247 int rc = CallSmc(kSMCGetKeyInfo, &In, pKeyData);
248 if (RT_SUCCESS(rc) && pKeyData->uResult == kSMCSuccess)
249 {
250 SMCPARAM Tmp = *pKeyData;
251
252 /* Get the key value. */
253 RT_ZERO(In);
254 In.uKey.u = uKey;
255 In.KeyInfo = Tmp.KeyInfo;
256 rc = CallSmc(kSMCReadKey, &In, pKeyData);
257 if (RT_SUCCESS(rc) && (pKeyData->uResult == kSMCSuccess || pKeyData->uResult == 0x85 /* not readable */))
258 {
259 pKeyData->uKey.u = uKey;
260 pKeyData->KeyInfo = Tmp.KeyInfo;
261 rc = VINF_SUCCESS;
262 }
263 else if (RT_SUCCESS(rc))
264 {
265 RTMsgError("kSMCReadKey failed on %.4s: %#x\n", &uKey, pKeyData->uResult);
266 rc = VERR_IO_GEN_FAILURE;
267 }
268 }
269 else if (RT_SUCCESS(rc))
270 {
271 RTMsgError("kSMCGetKeyInfo failed on %.4s: %#x\n", &uKey, pKeyData->uResult);
272 rc = VERR_IO_GEN_FAILURE;
273 }
274 return rc;
275}
276
277static void DisplayKey(SMCPARAM *pKey)
278{
279 pKey->uKey.u = RT_BE2H_U32(pKey->uKey.u);
280 pKey->KeyInfo.uDataType.u = RT_BE2H_U32(pKey->KeyInfo.uDataType.u);
281 RTPrintf("key=%4.4s type=%4.4s cb=%#04x fAttr=%#04x",
282 pKey->uKey.au8, pKey->KeyInfo.uDataType.au8, pKey->KeyInfo.cbData, pKey->KeyInfo.fAttr);
283 if (pKey->uResult == kSMCSuccess)
284 {
285 bool fPrintable = true;
286 for (uint32_t off = 0; off < pKey->KeyInfo.cbData; off++)
287 if (!RT_C_IS_PRINT(pKey->abValue[off]))
288 {
289 fPrintable = false;
290 break;
291 }
292 if (fPrintable)
293 RTPrintf(" %.*s\n", pKey->KeyInfo.cbData, pKey->abValue);
294 else
295 RTPrintf(" %.*Rhxs\n", pKey->KeyInfo.cbData, pKey->abValue);
296 }
297 else if (pKey->uResult == 0x85)
298 RTPrintf(" <not readable>\n");
299}
300
301static void DisplayKeyByName(uint32_t uKey)
302{
303 SMCPARAM Key;
304 int rc = GetKeyByName(uKey, &Key);
305 if (RT_SUCCESS(rc))
306 DisplayKey(&Key);
307}
308
309
310int main(int argc, char **argv)
311{
312 int rc = RTR3InitExe(argc, &argv, 0);
313 if (RT_FAILURE(rc))
314 return RTMsgInitFailure(rc);
315
316 rc = ConnectToSmc();
317 if (RT_SUCCESS(rc))
318 {
319 /*
320 * Dump the keys.
321 */
322 uint32_t cKeys;
323 rc = GetKeyCount(&cKeys);
324 if (RT_SUCCESS(rc))
325 RTPrintf("#Keys=%u\n", cKeys);
326 for (uint32_t iKey = 0; iKey < cKeys; iKey++)
327 {
328 SMCPARAM Key;
329 rc = GetKeyByIndex(iKey, &Key);
330 if (RT_SUCCESS(rc))
331 {
332 RTPrintf("%#06x: ", iKey);
333 DisplayKey(&Key);
334 }
335 }
336
337 /*
338 * Known keys that doesn't make it into the enumeration.
339 */
340 DisplayKeyByName('OSK0');
341 DisplayKeyByName('OSK1');
342 DisplayKeyByName('OSK2');
343
344 /* Negative checks, sometimes maybe. */
345 DisplayKeyByName('$Num');
346 DisplayKeyByName('MSTf');
347 DisplayKeyByName('MSDS');
348 DisplayKeyByName('LSOF');
349 }
350 DisconnectFromSmc();
351
352 if (RT_SUCCESS(rc))
353 return RTEXITCODE_SUCCESS;
354 return RTEXITCODE_FAILURE;
355}
356
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