VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/DevSmc.cpp@ 105745

Last change on this file since 105745 was 101222, checked in by vboxsync, 14 months ago

iprt/cdefs.h,DevSmc.cpp: Added RT_MAKE_U32_FROM_MSB_U8 to deal with the 'OSK0'/'OSK1' compiler warnings. Also added RT_MAKE_U64_FROM_MSB_U8 and RT_MAKE_U64_FROM_MSW_U16 completeness.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 57.0 KB
Line 
1/* $Id: DevSmc.cpp 101222 2023-09-21 14:41:09Z vboxsync $ */
2/** @file
3 * DevSmc - Apple System Management Controller.
4 *
5 * The SMC is controlling power, fans, take measurements (voltage, temperature,
6 * fan speed, ++), and lock Mac OS X to Apple hardware. For more details see:
7 * - http://en.wikipedia.org/wiki/System_Management_Controller
8 * - http://www.parhelia.ch/blog/statics/k3_keys.html
9 * - http://www.nosuchcon.org/talks/D1_02_Alex_Ninjas_and_Harry_Potter.pdf
10 */
11
12/*
13 * Copyright (C) 2013-2023 Oracle and/or its affiliates.
14 *
15 * This file is part of VirtualBox base platform packages, as
16 * available from https://www.virtualbox.org.
17 *
18 * This program is free software; you can redistribute it and/or
19 * modify it under the terms of the GNU General Public License
20 * as published by the Free Software Foundation, in version 3 of the
21 * License.
22 *
23 * This program is distributed in the hope that it will be useful, but
24 * WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
26 * General Public License for more details.
27 *
28 * You should have received a copy of the GNU General Public License
29 * along with this program; if not, see <https://www.gnu.org/licenses>.
30 *
31 * SPDX-License-Identifier: GPL-3.0-only
32 */
33
34
35/*********************************************************************************************************************************
36* Header Files *
37*********************************************************************************************************************************/
38#define LOG_GROUP LOG_GROUP_DEV_SMC
39#include <VBox/vmm/pdmdev.h>
40#include <VBox/log.h>
41#include <VBox/err.h>
42#include <iprt/assert.h>
43#include <iprt/string.h>
44#if defined(IN_RING0) && (defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86))
45# include <iprt/asm-amd64-x86.h>
46# include <iprt/once.h>
47#endif
48#if defined(RT_OS_DARWIN) && defined(IN_RING3) && !defined(VBOX_DEVICE_STRUCT_TESTCASE) /* drags in bad page size define */
49# include "IOKit/IOKitLib.h"
50#endif
51
52#include "VBoxDD.h"
53
54
55/*********************************************************************************************************************************
56* Defined Constants And Macros *
57*********************************************************************************************************************************/
58/** The current version of the saved state. */
59#define SMC_SAVED_STATE_VERSION 1 /** @todo later 2 */
60/** Empty saved state version. */
61#define SMC_SAVED_STATE_VERSION_BAKA 1
62
63/** The ring-0 operation number that attempts to get OSK0 and OSK1 from the real
64 * SMC. */
65#define SMC_CALLR0_READ_OSK 1
66
67
68/** @name Apple SMC port and register definitions.
69 * @{ */
70
71/** The first Apple SMC port. */
72#define SMC_PORT_FIRST 0x0300
73/** The number of registers (also ports). */
74#define SMC_REG_COUNT 0x0020
75
76/** The data register. */
77#define SMC_REG_DATA 0x00
78#define SMC_PORT_DATA (SMC_PORT_FIRST + SMC_REG_DATA)
79
80/** The command register. */
81#define SMC_REG_CMD 0x04
82#define SMC_PORT_CMD (SMC_PORT_FIRST + SMC_REG_CMD)
83
84/** Status code register. */
85#define SMC_REG_STATUS_CODE 0x1e
86#define SMC_PORT_STATUS_CODE (SMC_PORT_FIRST + SMC_REG_STATUS_CODE)
87/** @} */
88
89/** @name Apple SMC Commands.
90 * @{ */
91#define SMC_CMD_GET_KEY_VALUE 0x10
92#define SMC_CMD_PUT_KEY 0x11
93#define SMC_CMD_GET_KEY_BY_INDEX 0x12
94#define SMC_CMD_GET_KEY_INFO 0x13
95/** @} */
96
97/** @name Apple SMC Status Codes.
98 * @{ */
99#define SMC_STATUS_CD_SUCCESS UINT8_C(0x00)
100#define SMC_STATUS_CD_COMM_COLLISION UINT8_C(0x80)
101#define SMC_STATUS_CD_SPURIOUS_DATA UINT8_C(0x81)
102#define SMC_STATUS_CD_BAD_COMMAND UINT8_C(0x82)
103#define SMC_STATUS_CD_BAD_PARAMETER UINT8_C(0x83)
104#define SMC_STATUS_CD_KEY_NOT_FOUND UINT8_C(0x84)
105#define SMC_STATUS_CD_KEY_NOT_READABLE UINT8_C(0x85)
106#define SMC_STATUS_CD_KEY_NOT_WRITABLE UINT8_C(0x86)
107#define SMC_STATUS_CD_KEY_SIZE_MISMATCH UINT8_C(0x87)
108#define SMC_STATUS_CD_FRAMING_ERROR UINT8_C(0x88)
109#define SMC_STATUS_CD_BAD_ARGUMENT_ERROR UINT8_C(0x89)
110#define SMC_STATUS_CD_TIMEOUT_ERROR UINT8_C(0xb7)
111#define SMC_STATUS_CD_KEY_INDEX_RANGE_ERROR UINT8_C(0xb8)
112#define SMC_STATUS_CD_BAD_FUNC_PARAMETER UINT8_C(0xc0)
113#define SMC_STATUS_CD_EVENT_BUFF_WRONG_ORDER UINT8_C(0x??)
114#define SMC_STATUS_CD_EVENT_BUFF_READ_ERROR UINT8_C(0x??)
115#define SMC_STATUS_CD_DEVICE_ACCESS_ERROR UINT8_C(0xc7)
116#define SMC_STATUS_CD_UNSUPPORTED_FEATURE UINT8_C(0xcb)
117#define SMC_STATUS_CD_SMB_ACCESS_ERROR UINT8_C(0xcc)
118/** @} */
119
120/** @name Apple SMC Key Attributes.
121 * @{ */
122#define SMC_KEY_ATTR_PRIVATE UINT8_C(0x01)
123#define SMC_KEY_ATTR_UKN_0x02 UINT8_C(0x02)
124#define SMC_KEY_ATTR_UKN_0x04 UINT8_C(0x04)
125#define SMC_KEY_ATTR_CONST UINT8_C(0x08)
126#define SMC_KEY_ATTR_FUNCTION UINT8_C(0x10)
127#define SMC_KEY_ATTR_UKN_0x20 UINT8_C(0x20)
128#define SMC_KEY_ATTR_WRITE UINT8_C(0x40)
129#define SMC_KEY_ATTR_READ UINT8_C(0x80)
130/** @} */
131
132
133/** The index of the first enumerable key in g_aSmcKeys. */
134#define SMC_KEYIDX_FIRST_ENUM 2
135
136/** Macro for emitting a static DEVSMC4CHID initializer. */
137#define SMC4CH(ch1, ch2, ch3, ch4) { { ch1, ch2, ch3, ch4 } }
138
139/**
140 * Macro for comparing DEVSMC4CHID with a string value.
141 * @returns true if equal, false if not.
142 */
143#define SMC4CH_EQ(a_pSmcKey, a_sz4) ( (a_pSmcKey)->u32 == RT_MAKE_U32_FROM_U8(a_sz4[0], a_sz4[1], a_sz4[2], a_sz4[3]) )
144
145/** Indicates the we want a 2.x SMC. */
146#define VBOX_WITH_SMC_2_x
147
148
149/*********************************************************************************************************************************
150* Structures and Typedefs *
151*********************************************************************************************************************************/
152
153/**
154 * 4 char identifier
155 */
156typedef union DEVSMC4CHID
157{
158 /** Byte view. */
159 uint8_t ab[4];
160 /** 32-bit unsigned integer view. */
161 uint32_t u32;
162} DEVSMC4CHID;
163
164
165/**
166 * Current key data area for communicating with the guest.
167 */
168typedef struct DEVSMCCURKEY
169{
170 /** The key. */
171 DEVSMC4CHID Key;
172 /** The data type. */
173 DEVSMC4CHID Type;
174 /** Key attributes. */
175 uint8_t fAttr;
176 /** The value length. */
177 uint8_t cbValue;
178 uint8_t abAlignment[2];
179 /**
180 * The value union. 32 bytes is probably sufficient here, but we provide a
181 * little more room since it doesn't cost us anything. */
182 union
183 {
184 /** Byte view. */
185 uint8_t ab[128];
186 /** 16-bit view. */
187 uint16_t u16;
188 /** 32-bit view. */
189 uint32_t u32;
190 } Value;
191} DEVSMCCURKEY;
192AssertCompileSize(DEVSMCCURKEY, 128+12);
193/** Pointer to the current key buffer. */
194typedef DEVSMCCURKEY *PDEVSMCCURKEY;
195/** Const pointer to the current key buffer. */
196typedef DEVSMCCURKEY const *PCDEVSMCCURKEY;
197
198
199/**
200 * The device
201 */
202typedef struct DEVSMC
203{
204 /** The current command (SMC_PORT_CMD write). */
205 uint8_t bCmd;
206 /** Current key offset. */
207 uint8_t offKey;
208 /** Current value offset. */
209 uint8_t offValue;
210 /** Number of keys in the aKeys array. */
211 uint8_t cKeys;
212
213 /** The current key data the user is accessing. */
214 DEVSMCCURKEY CurKey;
215
216 /**
217 * Generic read/write register values.
218 *
219 * The DATA register entry is not used at all. The CMD register entry contains
220 * the state value.
221 */
222 union
223 {
224 /** Index register view. */
225 uint8_t abRegsRW[SMC_REG_COUNT];
226 /** Named register view. */
227 struct
228 {
229 uint8_t abUnknown0[0x04];
230 /** The current state (SMC_PORT_CMD read). */
231 uint8_t bState;
232 uint8_t abUnknown1[0x1e - 0x05];
233 /** The current status code (SMC_PORT_STATUS_CODE). */
234 uint8_t bStatusCode;
235 uint8_t abUnknown2[1];
236 } s;
237 } u;
238
239 /** @name Key data.
240 * @{ */
241 /** OSK0 and OSK1. */
242 char szOsk0And1[64+1];
243 /** $Num - unknown function. */
244 uint8_t bDollaryNumber;
245 /** MSSD - shutdown reason. */
246 uint8_t bShutdownReason;
247 /** NATJ - Ninja action timer job. */
248 uint8_t bNinjaActionTimerJob;
249 /** @} */
250
251 /** The I/O port registration handle. */
252 IOMIOPORTHANDLE hIoPorts;
253} DEVSMC;
254#ifndef _MSC_VER
255AssertCompileMembersAtSameOffset(DEVSMC, u.abRegsRW[SMC_REG_CMD], DEVSMC, u.s.bState);
256AssertCompileMembersAtSameOffset(DEVSMC, u.abRegsRW[SMC_REG_STATUS_CODE], DEVSMC, u.s.bStatusCode);
257#endif
258
259/** Pointer to the SMC state. */
260typedef DEVSMC *PDEVSMC;
261
262#ifndef VBOX_DEVICE_STRUCT_TESTCASE
263
264
265/**
266 * Method for retriving the key value and/or optionally also attributes.
267 *
268 * @returns Apple SMC Status Code.
269 * @param pThis The SMC instance data.
270 * @param pCurKey The current key structure (input / output).
271 * @param bCmd The current command (mostly for getters that also
272 * provides attributes or type info).
273 * @param pKeyDesc Pointer to the key descriptor so that the getter can
274 * service more than once key.
275 */
276typedef DECLCALLBACKTYPE(uint8_t, FNDEVSMCKEYGETTER,(PDEVSMC pThis, PDEVSMCCURKEY pCurKey, uint8_t bCmd,
277 struct DEVSMCKEYDESC const *pKeyDesc));
278
279/**
280 * Method for setting the key value.
281 *
282 * @returns Apple SMC Status Code.
283 * @param pThis The SMC instance data.
284 * @param pCurKey The current key structure (input / output).
285 * @param bCmd The current command (currently not relevant).
286 * @param pKeyDesc Pointer to the key descriptor so that the getter can
287 * service more than once key.
288 */
289typedef DECLCALLBACKTYPE(uint8_t, FNDEVSMCKEYPUTTER,(PDEVSMC pThis, PCDEVSMCCURKEY pCurKey, uint8_t bCmd,
290 struct DEVSMCKEYDESC const *pKeyDesc));
291
292/**
293 * Key descriptor.
294 */
295typedef struct DEVSMCKEYDESC
296{
297 /** The key 4 character identifier. */
298 DEVSMC4CHID Key;
299 /** Type 4 character identifier. 0 means the getter will set it dynamically. */
300 DEVSMC4CHID Type;
301 /** Getter method, see FNDEVSMCKEYGETTER. */
302 FNDEVSMCKEYGETTER *pfnGet;
303 /** Putter method, see FNDEVSMCKEYPUTTER. */
304 FNDEVSMCKEYPUTTER *pfnPut;
305 /** The keyvalue size. If 0 the pfnGet/pfnPut will define/check the size. */
306 uint8_t cbValue;
307 /** Attributes. 0 means the getter will set it dynamically. */
308 uint8_t fAttr;
309} DEVSMCKEYDESC;
310/** Pointer to a constant SMC key descriptor. */
311typedef DEVSMCKEYDESC const *PCDEVSMCKEYDESC;
312
313
314/*********************************************************************************************************************************
315* Internal Functions *
316*********************************************************************************************************************************/
317static FNDEVSMCKEYGETTER scmKeyGetOSKs;
318static FNDEVSMCKEYGETTER scmKeyGetKeyCount;
319static FNDEVSMCKEYGETTER scmKeyGetRevision;
320#ifdef VBOX_WITH_SMC_2_x
321static FNDEVSMCKEYGETTER scmKeyGetDollarAddress;
322static FNDEVSMCKEYGETTER scmKeyGetDollarNumber;
323static FNDEVSMCKEYPUTTER scmKeyPutDollarNumber;
324#endif
325static FNDEVSMCKEYGETTER scmKeyGetShutdownReason;
326static FNDEVSMCKEYPUTTER scmKeyPutShutdownReason;
327static FNDEVSMCKEYGETTER scmKeyGetNinjaTimerAction;
328static FNDEVSMCKEYPUTTER scmKeyPutNinjaTimerAction;
329static FNDEVSMCKEYGETTER scmKeyGetOne;
330static FNDEVSMCKEYGETTER scmKeyGetZero;
331
332
333/*********************************************************************************************************************************
334* Global Variables *
335*********************************************************************************************************************************/
336/**
337 * Apple SMC key descriptor table.
338 */
339static const DEVSMCKEYDESC g_aSmcKeys[] =
340{
341 /* Non-enum keys first. */
342 { SMC4CH('O','S','K','0'), SMC4CH('c','h','8','*'), scmKeyGetOSKs, NULL, 32, SMC_KEY_ATTR_READ | SMC_KEY_ATTR_FUNCTION },
343 { SMC4CH('O','S','K','1'), SMC4CH('c','h','8','*'), scmKeyGetOSKs, NULL, 32, SMC_KEY_ATTR_READ | SMC_KEY_ATTR_FUNCTION },
344
345 /* The first enum key is the #KEY value. */
346 { SMC4CH('#','K','E','Y'), SMC4CH('u','i','3','2'), scmKeyGetKeyCount, NULL, 4, SMC_KEY_ATTR_READ },
347# ifdef VBOX_WITH_SMC_2_x
348 { SMC4CH('$','A','d','r'), SMC4CH('u','i','3','2'), scmKeyGetDollarAddress, NULL, 4, SMC_KEY_ATTR_READ },
349 { SMC4CH('$','N','u','m'), SMC4CH('u','i','8',' '), scmKeyGetDollarNumber, scmKeyPutDollarNumber, 1, SMC_KEY_ATTR_READ | SMC_KEY_ATTR_WRITE | SMC_KEY_ATTR_PRIVATE },
350 { SMC4CH('B','E','M','B'), SMC4CH('f','l','a','g'), scmKeyGetOne, NULL, 1, SMC_KEY_ATTR_READ },
351# else
352 { SMC4CH('L','S','O','F'), SMC4CH('f','l','a','g'), scmKeyGetZero, NULL, 1, SMC_KEY_ATTR_READ },
353# endif
354 { SMC4CH('M','S','S','D'), SMC4CH('s','i','8',' '), scmKeyGetShutdownReason, scmKeyPutShutdownReason, 1, SMC_KEY_ATTR_READ | SMC_KEY_ATTR_WRITE | SMC_KEY_ATTR_PRIVATE },
355 /* MSDS is not present on MacPro3,1 nor MacBookPro10,1, so returning not found is fine. */
356# ifdef VBOX_WITH_SMC_2_x
357 { SMC4CH('M','S','T','f'), SMC4CH('u','i','8',' '), scmKeyGetZero, NULL, 1, SMC_KEY_ATTR_READ },
358# endif
359 { SMC4CH('N','A','T','J'), SMC4CH('u','i','8',' '), scmKeyGetNinjaTimerAction, scmKeyPutNinjaTimerAction, 1, SMC_KEY_ATTR_READ | SMC_KEY_ATTR_WRITE | SMC_KEY_ATTR_PRIVATE },
360 { SMC4CH('R','E','V',' '), SMC4CH('{','r','e','v'), scmKeyGetRevision, NULL, 6, SMC_KEY_ATTR_READ },
361/** @todo MSSP, NTOK and more. */
362};
363
364#if defined(IN_RING0) && (defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86))
365
366/** Do once for the SMC ring-0 static data (g_abOsk0And1, g_fHaveOsk). */
367static RTONCE g_SmcR0Once = RTONCE_INITIALIZER;
368/** Indicates whether we've successfully queried the OSK* keys. */
369static bool g_fHaveOsk = false;
370/** The OSK0 and OSK1 values. */
371static uint8_t g_abOsk0And1[32+32];
372
373
374/**
375 * Waits for the specified state on the host SMC.
376 *
377 * @returns success indicator.
378 * @param bState The desired state.
379 * @param pszWhat What we're currently doing. For the log.
380 */
381static bool devR0SmcWaitHostState(uint8_t bState, const char *pszWhat)
382{
383 uint8_t bCurState = 0; /* (MSC is potentially uninitialized) */
384 for (uint32_t cMsSleep = 1; cMsSleep <= 64; cMsSleep <<= 1)
385 {
386 RTThreadSleep(cMsSleep);
387 bCurState = ASMInU16(SMC_PORT_CMD);
388 if ((bCurState & 0xf) == bState)
389 return true;
390 }
391
392 LogRel(("devR0Smc: %s: bCurState=%#x, wanted %#x.\n", pszWhat, bCurState, bState));
393#if 0
394 uint8_t bCurStatus2 = ASMInU8(SMC_PORT_STATUS_CODE);
395 uint8_t bCurStatus3 = ASMInU8(SMC_PORT_STATUS_CODE);
396 uint16_t wCurStatus3 = ASMInU16(SMC_PORT_STATUS_CODE);
397 uint32_t dwCurStatus3 = ASMInU32(SMC_PORT_STATUS_CODE);
398 LogRel(("SMC: status2=%#x status3=%#x w=%#x dw=%#x\n", bCurStatus2, bCurStatus3, wCurStatus3, dwCurStatus3));
399#endif
400 return false;
401}
402
403
404/**
405 * Reads a key by name from the host SMC.
406 *
407 * @returns success indicator.
408 * @param pszName The key name, must be exactly 4 chars long.
409 * @param pbBuf The output buffer.
410 * @param cbBuf The buffer size. Max 32 bytes.
411 */
412static bool devR0SmcQueryHostKey(const char *pszName, uint8_t *pbBuf, size_t cbBuf)
413{
414 Assert(strlen(pszName) == 4);
415 Assert(cbBuf <= 32);
416 Assert(cbBuf > 0);
417
418 /*
419 * Issue the READ command.
420 */
421 uint32_t cMsSleep = 1;
422 for (;;)
423 {
424 ASMOutU32(SMC_PORT_CMD, SMC_CMD_GET_KEY_VALUE);
425 RTThreadSleep(cMsSleep);
426 uint8_t bCurState = ASMInU8(SMC_PORT_CMD);
427 if ((bCurState & 0xf) == 0xc)
428 break;
429 cMsSleep <<= 1;
430 if (cMsSleep > 64)
431 {
432 LogRel(("devR0Smc: %s: bCurState=%#x, wanted %#x.\n", "cmd", bCurState, 0xc));
433 return false;
434 }
435 }
436
437 /*
438 * Send it the key.
439 */
440 for (unsigned off = 0; off < 4; off++)
441 {
442 ASMOutU8(SMC_PORT_DATA, pszName[off]);
443 if (!devR0SmcWaitHostState(4, "key"))
444 return false;
445 }
446
447 /*
448 * The desired amount of output.
449 */
450 ASMOutU8(SMC_PORT_DATA, (uint8_t)cbBuf);
451
452 /*
453 * Read the output.
454 */
455 for (size_t off = 0; off < cbBuf; off++)
456 {
457 if (!devR0SmcWaitHostState(5, off ? "data" : "len"))
458 return false;
459 pbBuf[off] = ASMInU8(SMC_PORT_DATA);
460 }
461
462 LogRel(("SMC: pbBuf=%.*s\n", cbBuf, pbBuf));
463 return true;
464}
465
466
467/**
468 * RTOnce callback that initializes g_fHaveOsk and g_abOsk0And1.
469 *
470 * @returns VINF_SUCCESS.
471 * @param pvUserIgnored Ignored.
472 */
473static DECLCALLBACK(int) devR0SmcInitOnce(void *pvUserIgnored)
474{
475 g_fHaveOsk = devR0SmcQueryHostKey("OSK0", &g_abOsk0And1[0], 32)
476 && devR0SmcQueryHostKey("OSK1", &g_abOsk0And1[32], 32);
477
478#if 0
479 /*
480 * Dump the device registers.
481 */
482 for (uint16_t uPort = 0x300; uPort < 0x320; uPort ++)
483 LogRel(("SMC: %#06x=%#010x w={%#06x, %#06x}, b={%#04x %#04x %#04x %#04x}\n", uPort,
484 ASMInU32(uPort), ASMInU16(uPort), ASMInU16(uPort + 2),
485 ASMInU8(uPort), ASMInU8(uPort + 1), ASMInU8(uPort +2), ASMInU8(uPort + 3) ));
486#endif
487
488 NOREF(pvUserIgnored);
489 return VINF_SUCCESS;
490}
491
492
493/**
494 * @interface_method_impl{PDMDEVREGR0,pfnRequest}
495 */
496static DECLCALLBACK(int) devR0SmcReqHandler(PPDMDEVINS pDevIns, uint32_t uReq, uint64_t uArg)
497{
498 PDEVSMC pThis = PDMDEVINS_2_DATA(pDevIns, PDEVSMC);
499 int rc = VERR_INVALID_FUNCTION;
500 RT_NOREF_PV(uArg);
501
502 if (uReq == SMC_CALLR0_READ_OSK)
503 {
504 rc = RTOnce(&g_SmcR0Once, devR0SmcInitOnce, NULL);
505 if ( RT_SUCCESS(rc)
506 && g_fHaveOsk)
507 {
508 AssertCompile(sizeof(g_abOsk0And1) + 1 == sizeof(pThis->szOsk0And1));
509 memcpy(pThis->szOsk0And1, g_abOsk0And1, sizeof(pThis->szOsk0And1) - 1);
510 pThis->szOsk0And1[sizeof(pThis->szOsk0And1) - 1] = '\0';
511 }
512 }
513 return rc;
514}
515
516#endif /* IN_RING0 && (AMD64 || X86) */
517
518#if defined(IN_RING3) && defined(RT_OS_DARWIN)
519
520/**
521 * Preferred method to retrieve the SMC key.
522 *
523 * @param pabKey where to store the key.
524 * @param cbKey size of the buffer.
525 */
526static int getSmcKeyOs(char *pabKey, uint32_t cbKey)
527{
528 /*
529 * Method as described in Amit Singh's article:
530 * http://osxbook.com/book/bonus/chapter7/tpmdrmmyth/
531 */
532 typedef struct
533 {
534 uint32_t key;
535 uint8_t pad0[22];
536 uint32_t datasize;
537 uint8_t pad1[10];
538 uint8_t cmd;
539 uint32_t pad2;
540 uint8_t data[32];
541 } AppleSMCBuffer;
542
543 AssertReturn(cbKey >= 65, VERR_INTERNAL_ERROR);
544
545 RT_GCC_NO_WARN_DEPRECATED_BEGIN /* kIOMasterPortDefault: Deprecated since 12.0. */
546 io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault,
547 IOServiceMatching("AppleSMC"));
548 RT_GCC_NO_WARN_DEPRECATED_END
549 if (!service)
550 return VERR_NOT_FOUND;
551
552 io_connect_t port = (io_connect_t)0;
553 kern_return_t kr = IOServiceOpen(service, mach_task_self(), 0, &port);
554 IOObjectRelease(service);
555
556 if (kr != kIOReturnSuccess)
557 return RTErrConvertFromDarwin(kr);
558
559 AppleSMCBuffer inputStruct = { 0, {0}, 32, {0}, 5, };
560 AppleSMCBuffer outputStruct;
561 size_t cbOutputStruct = sizeof(outputStruct);
562
563 for (int i = 0; i < 2; i++)
564 {
565 inputStruct.key = i == 0 ? RT_MAKE_U32_FROM_MSB_U8('O','S','K','0') : RT_MAKE_U32_FROM_MSB_U8('O','S','K','1');
566 kr = IOConnectCallStructMethod((mach_port_t)port,
567 (uint32_t)2,
568 (const void *)&inputStruct,
569 sizeof(inputStruct),
570 (void *)&outputStruct,
571 &cbOutputStruct);
572 if (kr != kIOReturnSuccess)
573 {
574 IOServiceClose(port);
575 return RTErrConvertFromDarwin(kr);
576 }
577
578 for (int j = 0; j < 32; j++)
579 pabKey[j + i*32] = outputStruct.data[j];
580 }
581
582 IOServiceClose(port);
583
584 pabKey[64] = 0;
585
586 return VINF_SUCCESS;
587}
588
589#endif /* IN_RING3 && RT_OS_DARWIN */
590
591
592/** @callback_method_impl{FNDEVSMCKEYGETTER, OSK0 and OSK1} */
593static DECLCALLBACK(uint8_t) scmKeyGetOSKs(PDEVSMC pThis, PDEVSMCCURKEY pCurKey, uint8_t bCmd, PCDEVSMCKEYDESC pKeyDesc)
594{
595 RT_NOREF1(bCmd);
596 Assert(SMC4CH_EQ(&pKeyDesc->Key, "OSK0") || SMC4CH_EQ(&pKeyDesc->Key, "OSK1"));
597 const char *pszSrc = pThis->szOsk0And1;
598 if (SMC4CH_EQ(&pKeyDesc->Key, "OSK1"))
599 pszSrc += 32;
600 memcpy(pCurKey->Value.ab, pszSrc, 32);
601 return SMC_STATUS_CD_SUCCESS;
602}
603
604
605/** @callback_method_impl{FNDEVSMCKEYGETTER, \#KEY} */
606static DECLCALLBACK(uint8_t) scmKeyGetKeyCount(PDEVSMC pThis, PDEVSMCCURKEY pCurKey, uint8_t bCmd, PCDEVSMCKEYDESC pKeyDesc)
607{
608 RT_NOREF3(pThis, bCmd, pKeyDesc);
609 Assert(pKeyDesc == &g_aSmcKeys[SMC_KEYIDX_FIRST_ENUM]);
610 uint32_t cKeys = RT_ELEMENTS(g_aSmcKeys) - SMC_KEYIDX_FIRST_ENUM;
611 pCurKey->Value.u32 = RT_H2BE_U32(cKeys);
612 return SMC_STATUS_CD_SUCCESS;
613}
614
615
616/** @callback_method_impl{FNDEVSMCKEYGETTER, REV - Source revision.} */
617static DECLCALLBACK(uint8_t) scmKeyGetRevision(PDEVSMC pThis, PDEVSMCCURKEY pCurKey, uint8_t bCmd, PCDEVSMCKEYDESC pKeyDesc)
618{
619 RT_NOREF3(pThis, bCmd, pKeyDesc);
620#ifdef VBOX_WITH_SMC_2_x
621 pCurKey->Value.ab[0] = 0x02;
622 pCurKey->Value.ab[1] = 0x03;
623 pCurKey->Value.ab[2] = 0x0f;
624 pCurKey->Value.ab[3] = 0x00;
625 pCurKey->Value.ab[4] = 0x00;
626 pCurKey->Value.ab[5] = 0x35;
627#else
628 pCurKey->Value.ab[0] = 0x01;
629 pCurKey->Value.ab[1] = 0x25;
630 pCurKey->Value.ab[2] = 0x0f;
631 pCurKey->Value.ab[3] = 0x00;
632 pCurKey->Value.ab[4] = 0x00;
633 pCurKey->Value.ab[5] = 0x04;
634#endif
635 return SMC_STATUS_CD_SUCCESS;
636}
637
638#ifdef VBOX_WITH_SMC_2_x
639
640/** @callback_method_impl{FNDEVSMCKEYGETTER, $Adr - SMC address.} */
641static DECLCALLBACK(uint8_t) scmKeyGetDollarAddress(PDEVSMC pThis, PDEVSMCCURKEY pCurKey, uint8_t bCmd, PCDEVSMCKEYDESC pKeyDesc)
642{
643 RT_NOREF3(pThis, bCmd, pKeyDesc);
644 pCurKey->Value.u32 = RT_H2BE_U32(SMC_PORT_FIRST);
645 return VINF_SUCCESS;
646}
647
648
649/** @callback_method_impl{FNDEVSMCKEYGETTER, $Num - Some kind of number.} */
650static DECLCALLBACK(uint8_t) scmKeyGetDollarNumber(PDEVSMC pThis, PDEVSMCCURKEY pCurKey, uint8_t bCmd, PCDEVSMCKEYDESC pKeyDesc)
651{
652 RT_NOREF2(bCmd, pKeyDesc);
653 pCurKey->Value.ab[0] = pThis->bDollaryNumber;
654 return VINF_SUCCESS;
655}
656
657/** @callback_method_impl{FNDEVSMCKEYPUTTER, $Num - Some kind of number.} */
658static DECLCALLBACK(uint8_t) scmKeyPutDollarNumber(PDEVSMC pThis, PCDEVSMCCURKEY pCurKey, uint8_t bCmd, PCDEVSMCKEYDESC pKeyDesc)
659{
660 RT_NOREF2(bCmd, pKeyDesc);
661 Log(("scmKeyPutDollarNumber: %#x -> %#x\n", pThis->bDollaryNumber, pCurKey->Value.ab[0]));
662 pThis->bDollaryNumber = pCurKey->Value.ab[0];
663 return VINF_SUCCESS;
664}
665
666#endif /* VBOX_WITH_SMC_2_x */
667
668/** @callback_method_impl{FNDEVSMCKEYGETTER, MSSD - Machine Shutdown reason.} */
669static DECLCALLBACK(uint8_t) scmKeyGetShutdownReason(PDEVSMC pThis, PDEVSMCCURKEY pCurKey, uint8_t bCmd, PCDEVSMCKEYDESC pKeyDesc)
670{
671 RT_NOREF2(bCmd, pKeyDesc);
672 pCurKey->Value.ab[0] = pThis->bShutdownReason;
673 return SMC_STATUS_CD_SUCCESS;
674}
675
676
677/** @callback_method_impl{FNDEVSMCKEYPUTTER, MSSD - Machine Shutdown reason.} */
678static DECLCALLBACK(uint8_t) scmKeyPutShutdownReason(PDEVSMC pThis, PCDEVSMCCURKEY pCurKey, uint8_t bCmd, PCDEVSMCKEYDESC pKeyDesc)
679{
680 RT_NOREF2(bCmd, pKeyDesc);
681 Log(("scmKeyPutShutdownReason: %#x -> %#x\n", pThis->bShutdownReason, pCurKey->Value.ab[0]));
682 pThis->bShutdownReason = pCurKey->Value.ab[0];
683 return SMC_STATUS_CD_SUCCESS;
684}
685
686
687/** @callback_method_impl{FNDEVSMCKEYGETTER, MSSD - Ninja timer action job.} */
688static DECLCALLBACK(uint8_t)
689scmKeyGetNinjaTimerAction(PDEVSMC pThis, PDEVSMCCURKEY pCurKey, uint8_t bCmd, PCDEVSMCKEYDESC pKeyDesc)
690{
691 RT_NOREF2(bCmd, pKeyDesc);
692 pCurKey->Value.ab[0] = pThis->bNinjaActionTimerJob;
693 return SMC_STATUS_CD_SUCCESS;
694}
695
696
697/** @callback_method_impl{FNDEVSMCKEYPUTTER, NATJ - Ninja timer action job.} */
698static DECLCALLBACK(uint8_t)
699scmKeyPutNinjaTimerAction(PDEVSMC pThis, PCDEVSMCCURKEY pCurKey, uint8_t bCmd, PCDEVSMCKEYDESC pKeyDesc)
700{
701 RT_NOREF2(bCmd, pKeyDesc);
702 Log(("scmKeyPutNinjaTimerAction: %#x -> %#x\n", pThis->bNinjaActionTimerJob, pCurKey->Value.ab[0]));
703 pThis->bNinjaActionTimerJob = pCurKey->Value.ab[0];
704 return SMC_STATUS_CD_SUCCESS;
705}
706
707#ifdef VBOX_WITH_SMC_2_x
708
709/** @callback_method_impl{FNDEVSMCKEYGETTER, Generic one getter.} */
710static DECLCALLBACK(uint8_t) scmKeyGetOne(PDEVSMC pThis, PDEVSMCCURKEY pCurKey, uint8_t bCmd, PCDEVSMCKEYDESC pKeyDesc)
711{
712 RT_NOREF2(pThis, bCmd);
713 memset(&pCurKey->Value.ab[0], 0, pKeyDesc->cbValue);
714 pCurKey->Value.ab[pKeyDesc->cbValue - 1] = 1;
715 return SMC_STATUS_CD_SUCCESS;
716}
717
718#endif /* VBOX_WITH_SMC_2_x */
719
720/** @callback_method_impl{FNDEVSMCKEYGETTER, Generic zero getter.} */
721static DECLCALLBACK(uint8_t) scmKeyGetZero(PDEVSMC pThis, PDEVSMCCURKEY pCurKey, uint8_t bCmd, PCDEVSMCKEYDESC pKeyDesc)
722{
723 RT_NOREF2(pThis, bCmd);
724 memset(&pCurKey->Value.ab[0], 0, pKeyDesc->cbValue);
725 return SMC_STATUS_CD_SUCCESS;
726}
727
728
729/**
730 * Looks up a key and copies its value and attributes into the CurKey.
731 *
732 * @returns Key index on success, UINT32_MAX on failure.
733 * @param uKeyValue The key value (DEVSMC4CHID.u32).
734 */
735static uint32_t smcKeyLookup(uint32_t uKeyValue)
736{
737 uint32_t iKey = RT_ELEMENTS(g_aSmcKeys);
738 while (iKey-- > 0)
739 if (g_aSmcKeys[iKey].Key.u32 == uKeyValue)
740 return iKey;
741 return UINT32_MAX;
742}
743
744
745/**
746 * Looks up a key and copies its value and attributes into the CurKey.
747 *
748 * @returns Apple SMC Status Code.
749 * @param pThis The SMC instance data.
750 */
751static uint8_t smcKeyGetByName(PDEVSMC pThis)
752{
753 uint8_t bRc;
754#ifdef LOG_ENABLED
755 uint32_t const uKeyValueLog = RT_H2LE_U32(pThis->CurKey.Key.u32);
756#endif
757 uint32_t iKey = smcKeyLookup(pThis->CurKey.Key.u32);
758 if (iKey != UINT32_MAX)
759 {
760 if ( g_aSmcKeys[iKey].cbValue == pThis->CurKey.cbValue
761 || !g_aSmcKeys[iKey].cbValue)
762 {
763 pThis->CurKey.Type = g_aSmcKeys[iKey].Type;
764 pThis->CurKey.fAttr = g_aSmcKeys[iKey].fAttr;
765 RT_ZERO(pThis->CurKey.Value);
766 if (g_aSmcKeys[iKey].pfnGet)
767 {
768 bRc = g_aSmcKeys[iKey].pfnGet(pThis, &pThis->CurKey, pThis->bCmd, &g_aSmcKeys[iKey]);
769 if (bRc == SMC_STATUS_CD_SUCCESS)
770 {
771 LogFlow(("smcKeyGetByName: key=%4.4s value=%.*Rhxs\n",
772 &uKeyValueLog, pThis->CurKey.cbValue, &pThis->CurKey.Value));
773 return SMC_STATUS_CD_SUCCESS;
774 }
775
776 Log(("smcKeyGetByName: key=%4.4s getter failed! bRc=%#x\n", &uKeyValueLog, bRc));
777 }
778 else
779 {
780 Log(("smcKeyGetByName: key=%4.4s is not readable!\n", &uKeyValueLog));
781 bRc = SMC_STATUS_CD_KEY_NOT_READABLE;
782 }
783 }
784 else
785 {
786 Log(("smcKeyGetByName: Wrong value size; user=%#x smc=%#x key=%4.4s !\n",
787 pThis->CurKey.cbValue, g_aSmcKeys[iKey].cbValue, &uKeyValueLog));
788 bRc = SMC_STATUS_CD_KEY_SIZE_MISMATCH;
789 }
790 }
791 else
792 {
793 Log(("smcKeyGetByName: Key not found! key=%4.4s size=%#x\n", &uKeyValueLog, pThis->CurKey.cbValue));
794 bRc = SMC_STATUS_CD_KEY_NOT_FOUND;
795 }
796
797 RT_ZERO(pThis->CurKey);
798 return bRc;
799}
800
801
802/**
803 * Looks up a key by index and copies its name (and attributes) into the CurKey.
804 *
805 * @returns Apple SMC Status Code.
806 * @param pThis The SMC instance data.
807 */
808static uint8_t smcKeyGetByIndex(PDEVSMC pThis)
809{
810 uint8_t bRc;
811 uint32_t iKey = RT_BE2H_U32(pThis->CurKey.Key.u32);
812 if (iKey < RT_ELEMENTS(g_aSmcKeys) - SMC_KEYIDX_FIRST_ENUM)
813 {
814 pThis->CurKey.Key = g_aSmcKeys[iKey].Key;
815 pThis->CurKey.Type = g_aSmcKeys[iKey].Type;
816 pThis->CurKey.fAttr = g_aSmcKeys[iKey].fAttr;
817 pThis->CurKey.cbValue = g_aSmcKeys[iKey].cbValue;
818 RT_ZERO(pThis->CurKey.Value);
819 Log(("smcKeyGetByIndex: %#x -> %c%c%c%c\n", iKey,
820 pThis->CurKey.Key.ab[3], pThis->CurKey.Key.ab[2], pThis->CurKey.Key.ab[1], pThis->CurKey.Key.ab[0]));
821 bRc = SMC_STATUS_CD_SUCCESS;
822 }
823 else
824 {
825 Log(("smcKeyGetByIndex: Key out or range: %#x, max %#x\n", iKey, RT_ELEMENTS(g_aSmcKeys) - SMC_KEYIDX_FIRST_ENUM));
826 bRc = SMC_STATUS_CD_KEY_NOT_FOUND;
827 }
828 return bRc;
829}
830
831
832/**
833 * Looks up a key by index and copies its attributes into the CurKey.
834 *
835 * @returns Apple SMC Status Code.
836 * @param pThis The SMC instance data.
837 */
838static uint8_t smcKeyGetAttrByName(PDEVSMC pThis)
839{
840 uint8_t bRc;
841#ifdef LOG_ENABLED
842 uint32_t const uKeyValueLog = RT_H2LE_U32(pThis->CurKey.Key.u32);
843#endif
844 uint32_t iKey = smcKeyLookup(pThis->CurKey.Key.u32);
845 if (iKey != UINT32_MAX)
846 {
847 pThis->CurKey.Type = g_aSmcKeys[iKey].Type;
848 pThis->CurKey.fAttr = g_aSmcKeys[iKey].fAttr;
849 pThis->CurKey.cbValue = g_aSmcKeys[iKey].cbValue;
850 RT_ZERO(pThis->CurKey.Value);
851 if (g_aSmcKeys[iKey].cbValue)
852 bRc = SMC_STATUS_CD_SUCCESS;
853 else
854 bRc = g_aSmcKeys[iKey].pfnGet(pThis, &pThis->CurKey, pThis->bCmd, &g_aSmcKeys[iKey]);
855 if (bRc == SMC_STATUS_CD_SUCCESS)
856 {
857 LogFlow(("smcKeyGetAttrByName: key=%4.4s value=%.*Rhxs\n",
858 &uKeyValueLog, pThis->CurKey.cbValue, &pThis->CurKey.Value));
859 return SMC_STATUS_CD_SUCCESS;
860 }
861
862 Log(("smcKeyGetAttrByName: key=%4.4s getter failed! bRc=%#x\n", &uKeyValueLog, bRc));
863 }
864 else
865 {
866 Log(("smcKeyGetAttrByName: Key not found! key=%4.4s size=%#x\n", &uKeyValueLog, pThis->CurKey.cbValue));
867 bRc = SMC_STATUS_CD_KEY_NOT_FOUND;
868 }
869
870 RT_ZERO(pThis->CurKey);
871 return bRc;
872}
873
874
875static uint8_t smcKeyPutPrepare(PDEVSMC pThis)
876{
877 RT_NOREF1(pThis);
878 return 0;
879}
880
881static uint8_t smcKeyPutValue(PDEVSMC pThis)
882{
883 RT_NOREF1(pThis);
884 return 0;
885}
886
887
888/**
889 * Data register read.
890 *
891 * @returns VINF_SUCCESS or VINF_IOM_R3_IOPORT_WRITE.
892 * @param uReg The register number.
893 * @param pbValue Where to return the value.
894 */
895static VBOXSTRICTRC smcRegData_r(PDEVSMC pThis, uint8_t uReg, uint8_t *pbValue)
896{
897 RT_NOREF1(uReg);
898 switch (pThis->bCmd)
899 {
900 case SMC_CMD_GET_KEY_VALUE:
901 if ( pThis->u.s.bState == 0x05
902 && pThis->offValue < pThis->CurKey.cbValue)
903 {
904 *pbValue = pThis->CurKey.Value.ab[pThis->offValue];
905 if (++pThis->offValue >= pThis->CurKey.cbValue)
906 pThis->u.s.bState = 0x00;
907 pThis->u.s.bStatusCode = SMC_STATUS_CD_SUCCESS;
908 }
909 else
910 {
911 Log(("smcRegData_r: Reading too much or at wrong time during SMC_CMD_GET_KEY_INFO! bState=%#x offValue=%#x\n",
912 pThis->u.s.bState, pThis->offValue));
913 pThis->u.s.bState = 0x00;
914 pThis->u.s.bStatusCode = SMC_STATUS_CD_SPURIOUS_DATA; /** @todo check status code */
915 }
916 break;
917
918 case SMC_CMD_GET_KEY_INFO:
919 if ( pThis->u.s.bState == 0x05
920 && pThis->offValue < 6)
921 {
922 if (pThis->offValue == 0)
923 *pbValue = pThis->CurKey.cbValue;
924 else if (pThis->offValue < 1 + 4)
925 *pbValue = pThis->CurKey.Type.ab[pThis->offValue - 1];
926 else
927 *pbValue = pThis->CurKey.fAttr;
928 if (++pThis->offValue >= 6)
929 pThis->u.s.bState = 0x00;
930 pThis->u.s.bStatusCode = SMC_STATUS_CD_SUCCESS;
931 }
932 else
933 {
934 Log(("smcRegData_r: Reading too much or at wrong time during SMC_CMD_GET_KEY_INFO! bState=%#x offValue=%#x\n",
935 pThis->u.s.bState, pThis->offValue));
936 pThis->u.s.bState = 0x00;
937 pThis->u.s.bStatusCode = SMC_STATUS_CD_SPURIOUS_DATA; /** @todo check status code */
938 }
939 break;
940
941 case SMC_CMD_GET_KEY_BY_INDEX:
942 if ( pThis->u.s.bState == 0x05
943 && pThis->offValue < sizeof(pThis->CurKey.Key))
944 {
945 *pbValue = pThis->CurKey.Key.ab[pThis->offValue];
946 if (++pThis->offValue >= sizeof(pThis->CurKey.Key))
947 pThis->u.s.bState = 0x00;
948 pThis->u.s.bStatusCode = SMC_STATUS_CD_SUCCESS;
949 }
950 else
951 {
952 Log(("smcRegData_r: Reading too much or at wrong time during GET_KEY_BY_INDEX! bState=%#x offValue=%#x\n",
953 pThis->u.s.bState, pThis->offValue));
954 pThis->u.s.bState = 0x00;
955 pThis->u.s.bStatusCode = SMC_STATUS_CD_SPURIOUS_DATA; /** @todo check status code */
956 }
957 break;
958
959 case SMC_CMD_PUT_KEY:
960 Log(("smcRegData_r: Attempting to read data during PUT_KEY!\n"));
961 *pbValue = 0xff;
962 pThis->u.s.bState = 0;
963 pThis->u.s.bStatusCode = SMC_STATUS_CD_SPURIOUS_DATA;
964 break;
965
966 default:
967 Log(("smcRegData_r: Unknown command attempts reading data\n"));
968 *pbValue = 0xff;
969 pThis->u.s.bState = 0;
970 pThis->u.s.bStatusCode = SMC_STATUS_CD_SPURIOUS_DATA;
971 break;
972 }
973
974 return VINF_SUCCESS;
975}
976
977
978/**
979 * Data register write.
980 *
981 * @returns VINF_SUCCESS or VINF_IOM_R3_IOPORT_WRITE.
982 * @param uReg The register number.
983 * @param bValue The value being written.
984 */
985static VBOXSTRICTRC smcRegData_w(PDEVSMC pThis, uint8_t uReg, uint8_t bValue)
986{
987 RT_NOREF1(uReg);
988 switch (pThis->bCmd)
989 {
990 /*
991 * Get or put key value.
992 *
993 * 5 bytes written, first 4 is the key the 5th is the value size. In
994 * the case of a put the value bytes are then written, while a get will
995 * read the value bytes.
996 */
997 case SMC_CMD_GET_KEY_VALUE:
998 case SMC_CMD_PUT_KEY:
999 if (pThis->offKey < 4)
1000 {
1001 /* Key byte. */
1002 pThis->CurKey.Key.ab[pThis->offKey++] = bValue;
1003 pThis->u.s.bState = 0x04;
1004 pThis->u.s.bStatusCode = SMC_STATUS_CD_SUCCESS;
1005 }
1006 else if (pThis->offKey == 4)
1007 {
1008 /* Data length. */
1009 pThis->u.s.bState = 0;
1010 if (bValue <= sizeof(pThis->CurKey.Value))
1011 {
1012 pThis->CurKey.cbValue = bValue;
1013 pThis->offKey = 5;
1014 Assert(pThis->offValue == 0);
1015
1016 if (pThis->bCmd == SMC_CMD_GET_KEY_VALUE)
1017 pThis->u.s.bStatusCode = smcKeyGetByName(pThis);
1018 else
1019 pThis->u.s.bStatusCode = smcKeyPutPrepare(pThis);
1020 if (pThis->u.s.bStatusCode == SMC_STATUS_CD_SUCCESS)
1021 pThis->u.s.bState = 0x05;
1022 }
1023 else
1024 {
1025 Log(("smcRegData_w: Guest attempts to get/put too many value bytes: %#x (max %#x)!\n",
1026 bValue, sizeof(pThis->CurKey.Value)));
1027 pThis->u.s.bStatusCode = SMC_STATUS_CD_KEY_SIZE_MISMATCH; /** @todo check this case! */
1028 }
1029 }
1030 else if ( pThis->bCmd == SMC_CMD_PUT_KEY
1031 && pThis->offValue < pThis->CurKey.cbValue)
1032 {
1033 /* More value bytes for put key action. */
1034 pThis->CurKey.Value.ab[pThis->offValue++] = bValue;
1035 if (pThis->offValue != pThis->CurKey.cbValue)
1036 pThis->u.s.bState = 0x05;
1037 else
1038 {
1039 pThis->u.s.bState = 0x00;
1040 pThis->u.s.bStatusCode = smcKeyPutValue(pThis);
1041 }
1042 }
1043 else
1044 {
1045 Log(("smcRegData_w: Writing too much data on %s command!\n", pThis->bCmd == SMC_CMD_PUT_KEY ? "put" : "get"));
1046 pThis->u.s.bState = 0x00;
1047 pThis->u.s.bStatusCode = SMC_STATUS_CD_SPURIOUS_DATA;
1048 }
1049 break;
1050
1051 /*
1052 * Get key info and key by index seems to take action after the last
1053 * key char is written. They then both go into a data reading phase.
1054 */
1055 case SMC_CMD_GET_KEY_INFO:
1056 case SMC_CMD_GET_KEY_BY_INDEX:
1057 if (pThis->offKey < 4)
1058 {
1059 pThis->CurKey.Key.ab[pThis->offKey] = bValue;
1060 if (++pThis->offKey == 4)
1061 {
1062 if (pThis->bCmd == SMC_CMD_GET_KEY_BY_INDEX)
1063 pThis->u.s.bStatusCode = smcKeyGetByIndex(pThis);
1064 else
1065 pThis->u.s.bStatusCode = smcKeyGetAttrByName(pThis);
1066 pThis->u.s.bState = pThis->u.s.bStatusCode == SMC_STATUS_CD_SUCCESS ? 0x05 : 0x00;
1067 }
1068 else
1069 {
1070 pThis->u.s.bState = 0x04;
1071 pThis->u.s.bStatusCode = SMC_STATUS_CD_SUCCESS;
1072 }
1073 }
1074 else
1075 {
1076 Log(("smcRegData_w: Writing data beyond 5th byte on get %s command!\n",
1077 pThis->bCmd == SMC_CMD_GET_KEY_INFO ? "info" : "by index"));
1078 pThis->u.s.bState = 0x00;
1079 pThis->u.s.bStatusCode = SMC_STATUS_CD_SPURIOUS_DATA;
1080 }
1081 break;
1082
1083 default:
1084 Log(("smcRegData_w: Unknown command %#x!\n", bValue));
1085 pThis->u.s.bState = 0x00; /** @todo Check statuses with real HW. */
1086 pThis->u.s.bStatusCode = SMC_STATUS_CD_BAD_COMMAND;
1087 break;
1088 }
1089 return VINF_SUCCESS;
1090}
1091
1092
1093/**
1094 * Command register write.
1095 *
1096 * @returns VINF_SUCCESS or VINF_IOM_R3_IOPORT_WRITE.
1097 * @param uReg The register number.
1098 * @param bValue The value being written.
1099 */
1100static VBOXSTRICTRC smcRegCmd_w(PDEVSMC pThis, uint8_t uReg, uint8_t bValue)
1101{
1102 LogFlow(("smcRegCmd_w: New command: %#x (old=%#x)\n", bValue, pThis->bCmd)); NOREF(uReg);
1103
1104 pThis->bCmd = bValue;
1105
1106 /* Validate the command. */
1107 switch (bValue)
1108 {
1109 case SMC_CMD_GET_KEY_VALUE:
1110 case SMC_CMD_PUT_KEY:
1111 case SMC_CMD_GET_KEY_BY_INDEX:
1112 case SMC_CMD_GET_KEY_INFO:
1113 pThis->u.s.bState = 0x0c;
1114 pThis->u.s.bStatusCode = SMC_STATUS_CD_SUCCESS;
1115 break;
1116
1117 default:
1118 Log(("SMC: Unknown command %#x!\n", bValue));
1119 pThis->u.s.bState = 0x00; /** @todo Check state with real HW. */
1120 pThis->u.s.bStatusCode = SMC_STATUS_CD_BAD_COMMAND;
1121 break;
1122 }
1123
1124 /* Reset the value/key related state. */
1125 pThis->offKey = 0;
1126 pThis->offValue = 0;
1127 pThis->CurKey.Key.u32 = 0;
1128 pThis->CurKey.cbValue = 0;
1129
1130 return VINF_SUCCESS;
1131}
1132
1133
1134/**
1135 * Generic register write.
1136 *
1137 * @returns VINF_SUCCESS or VINF_IOM_R3_IOPORT_WRITE.
1138 * @param uReg The register number.
1139 * @param bValue The value being written.
1140 */
1141static VBOXSTRICTRC smcRegGen_w(PDEVSMC pThis, uint8_t uReg, uint8_t bValue)
1142{
1143 Log(("smcRegGen_w: %#04x: %#x -> %#x (write)\n", uReg, pThis->u.abRegsRW[uReg], bValue));
1144 pThis->u.abRegsRW[uReg] = bValue;
1145 return VINF_SUCCESS;
1146}
1147
1148
1149/**
1150 * Read from register that isn't writable and reads as 0xFF.
1151 *
1152 * @returns VINF_SUCCESS or VINF_IOM_R3_IOPORT_WRITE.
1153 * @param uReg The register number.
1154 * @param pbValue Where to return the value.
1155 */
1156static VBOXSTRICTRC smcRegGen_r(PDEVSMC pThis, uint8_t uReg, uint8_t *pbValue)
1157{
1158 Log(("smcRegGen_r: %#04x: %#x (read)\n", uReg, pThis->u.abRegsRW[uReg]));
1159 *pbValue = pThis->u.abRegsRW[uReg];
1160 return VINF_SUCCESS;
1161}
1162
1163
1164/**
1165 * Write to register that isn't writable and reads as 0xFF.
1166 *
1167 * @returns VINF_SUCCESS or VINF_IOM_R3_IOPORT_WRITE.
1168 * @param uReg The register number.
1169 * @param bValue The value being written.
1170 */
1171static VBOXSTRICTRC smcRegFF_w(PDEVSMC pThis, uint8_t uReg, uint8_t bValue)
1172{
1173 RT_NOREF3(pThis, uReg, bValue);
1174 Log(("SMC: %#04x: Writing %#x to unknown register!\n", uReg, bValue));
1175 return VINF_SUCCESS;
1176}
1177
1178
1179/**
1180 * Read from register that isn't writable and reads as 0xFF.
1181 *
1182 * @returns VINF_SUCCESS or VINF_IOM_R3_IOPORT_WRITE.
1183 * @param uReg The register number.
1184 * @param pbValue Where to return the value.
1185 */
1186static VBOXSTRICTRC smcRegFF_r(PDEVSMC pThis, uint8_t uReg, uint8_t *pbValue)
1187{
1188 RT_NOREF2(pThis, uReg);
1189 Log(("SMC: %#04x: Reading from unknown register!\n", uReg));
1190 *pbValue = 0xff;
1191 return VINF_SUCCESS;
1192}
1193
1194
1195
1196/**
1197 * SMC register handlers (indexed by relative I/O port).
1198 *
1199 * The device seems to be all byte registers and will split wider
1200 * accesses between registers like if it was MMIO. To better illustrate it
1201 * here is the output of the code in devR0SmcInitOnce on a MacPro3,1:
1202 * @verbatim
1203 * SMC: 0x0300=0xffffff63 w={0xff63, 0xffff}, b={0x63 0xff 0xff 0xff}
1204 * SMC: 0x0301=0x0cffffff w={0xffff, 0x0cff}, b={0xff 0xff 0xff 0x0c}
1205 * SMC: 0x0302=0xff0cffff w={0xffff, 0xff0c}, b={0xff 0xff 0x0c 0xff}
1206 * SMC: 0x0303=0xffff0cff w={0x0cff, 0xffff}, b={0xff 0x0c 0xff 0xff}
1207 * SMC: 0x0304=0xffffff0c w={0xff0c, 0xffff}, b={0x0c 0xff 0xff 0xff}
1208 * SMC: 0x0305=0xffffffff w={0xffff, 0xffff}, b={0xff 0xff 0xff 0xff}
1209 * SMC: 0x0306=0xffffffff w={0xffff, 0xffff}, b={0xff 0xff 0xff 0xff}
1210 * SMC: 0x0307=0xffffffff w={0xffff, 0xffff}, b={0xff 0xff 0xff 0xff}
1211 * SMC: 0x0308=0xffffffff w={0xffff, 0xffff}, b={0xff 0xff 0xff 0xff}
1212 * SMC: 0x0309=0xffffffff w={0xffff, 0xffff}, b={0xff 0xff 0xff 0xff}
1213 * SMC: 0x030a=0xffffffff w={0xffff, 0xffff}, b={0xff 0xff 0xff 0xff}
1214 * SMC: 0x030b=0xffffffff w={0xffff, 0xffff}, b={0xff 0xff 0xff 0xff}
1215 * SMC: 0x030c=0xffffffff w={0xffff, 0xffff}, b={0xff 0xff 0xff 0xff}
1216 * SMC: 0x030d=0x00ffffff w={0xffff, 0x00ff}, b={0xff 0xff 0xff 0x00}
1217 * SMC: 0x030e=0x0000ffff w={0xffff, 0x0000}, b={0xff 0xff 0x00 0x00}
1218 * SMC: 0x030f=0x000000ff w={0x00ff, 0x0000}, b={0xff 0x00 0x00 0x00}
1219 * SMC: 0x0310=0x00000000 w={0x0000, 0x0000}, b={0x00 0x00 0x00 0x00}
1220 * SMC: 0x0311=0x00000000 w={0x0000, 0x0000}, b={0x00 0x00 0x00 0x00}
1221 * SMC: 0x0312=0x00000000 w={0x0000, 0x0000}, b={0x00 0x00 0x00 0x00}
1222 * SMC: 0x0313=0x00000000 w={0x0000, 0x0000}, b={0x00 0x00 0x00 0x00}
1223 * SMC: 0x0314=0x00000000 w={0x0000, 0x0000}, b={0x00 0x00 0x00 0x00}
1224 * SMC: 0x0315=0x00000000 w={0x0000, 0x0000}, b={0x00 0x00 0x00 0x00}
1225 * SMC: 0x0316=0x00000000 w={0x0000, 0x0000}, b={0x00 0x00 0x00 0x00}
1226 * SMC: 0x0317=0x00000000 w={0x0000, 0x0000}, b={0x00 0x00 0x00 0x00}
1227 * SMC: 0x0318=0x00000000 w={0x0000, 0x0000}, b={0x00 0x00 0x00 0x00}
1228 * SMC: 0x0319=0xbe000000 w={0x0000, 0xbe00}, b={0x00 0x00 0x00 0xbe}
1229 * SMC: 0x031a=0xbabe0000 w={0x0000, 0xbabe}, b={0x00 0x00 0xbe 0xba}
1230 * SMC: 0x031b=0x00babe00 w={0xbe00, 0x00ba}, b={0x00 0xbe 0xba 0x00}
1231 * SMC: 0x031c=0xbe00babe w={0xbabe, 0xbe00}, b={0xbe 0xba 0x00 0xbe}
1232 * SMC: 0x031d=0xffbe00ba w={0x00ba, 0xffbe}, b={0xba 0x00 0xbe 0xff}
1233 * SMC: 0x031e=0xffffbe00 w={0xbe00, 0xffff}, b={0x00 0xbe 0xff 0xff}
1234 * SMC: 0x031f=0xffffffbe w={0xffbe, 0xffff}, b={0xbe 0xff 0xff 0xff}
1235 * @endverbatim
1236 *
1237 * The last dword is writable (0xbeXXbabe) where in the register at 0x1e is some
1238 * kind of status register for qualifying search failures and the like and will
1239 * be cleared under certain conditions. The whole dword can be written and read
1240 * back unchanged, according to my experiments. The 0x00 and 0x04 registers
1241 * does not read back what is written.
1242 *
1243 * My guess is that the 0xff values indicates ports that are not writable and
1244 * hardwired to 0xff, while the other values indicates ports that can be written
1245 * to and normally read back as written. I'm not going to push my luck too far
1246 * wrt to exact behavior until I see the guest using the registers.
1247 */
1248static const struct
1249{
1250 VBOXSTRICTRC (*pfnWrite)(PDEVSMC pThis, uint8_t uReg, uint8_t bValue);
1251 VBOXSTRICTRC (*pfnRead)(PDEVSMC pThis, uint8_t uReg, uint8_t *pbValue);
1252} g_aSmcRegs[SMC_REG_COUNT] =
1253{
1254 /* [0x00] = */ { smcRegData_w, smcRegData_r },
1255 /* [0x01] = */ { smcRegFF_w, smcRegFF_r },
1256 /* [0x02] = */ { smcRegFF_w, smcRegFF_r },
1257 /* [0x03] = */ { smcRegFF_w, smcRegFF_r },
1258 /* [0x04] = */ { smcRegCmd_w, smcRegGen_r },
1259 /* [0x05] = */ { smcRegFF_w, smcRegFF_r },
1260 /* [0x06] = */ { smcRegFF_w, smcRegFF_r },
1261 /* [0x07] = */ { smcRegFF_w, smcRegFF_r },
1262 /* [0x08] = */ { smcRegFF_w, smcRegFF_r },
1263 /* [0x09] = */ { smcRegFF_w, smcRegFF_r },
1264 /* [0x0a] = */ { smcRegFF_w, smcRegFF_r },
1265 /* [0x0b] = */ { smcRegFF_w, smcRegFF_r },
1266 /* [0x0c] = */ { smcRegFF_w, smcRegFF_r },
1267 /* [0x0d] = */ { smcRegFF_w, smcRegFF_r },
1268 /* [0x0e] = */ { smcRegFF_w, smcRegFF_r },
1269 /* [0x0f] = */ { smcRegFF_w, smcRegFF_r },
1270 /* [0x10] = */ { smcRegGen_w, smcRegGen_r },
1271 /* [0x11] = */ { smcRegGen_w, smcRegGen_r },
1272 /* [0x12] = */ { smcRegGen_w, smcRegGen_r },
1273 /* [0x13] = */ { smcRegGen_w, smcRegGen_r },
1274 /* [0x14] = */ { smcRegGen_w, smcRegGen_r },
1275 /* [0x15] = */ { smcRegGen_w, smcRegGen_r },
1276 /* [0x16] = */ { smcRegGen_w, smcRegGen_r },
1277 /* [0x17] = */ { smcRegGen_w, smcRegGen_r },
1278 /* [0x18] = */ { smcRegGen_w, smcRegGen_r },
1279 /* [0x19] = */ { smcRegGen_w, smcRegGen_r },
1280 /* [0x1a] = */ { smcRegGen_w, smcRegGen_r },
1281 /* [0x1b] = */ { smcRegGen_w, smcRegGen_r },
1282 /* [0x1c] = */ { smcRegGen_w, smcRegGen_r },
1283 /* [0x1d] = */ { smcRegGen_w, smcRegGen_r },
1284 /* [0x1e] = */ { smcRegGen_w, smcRegGen_r },
1285 /* [0x1f] = */ { smcRegGen_w, smcRegGen_r },
1286};
1287
1288
1289/**
1290 * @callback_method_impl{FNIOMIOPORTNEWOUT}
1291 */
1292static DECLCALLBACK(VBOXSTRICTRC) smcIoPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
1293{
1294 RT_NOREF1(pvUser);
1295#ifndef IN_RING3
1296 if (cb > 1)
1297 {
1298 Log3(("smcIoPortWrite: %#04x write access: %#x (LB %u) -> ring-3\n", offPort, u32, cb));
1299 return VINF_IOM_R3_IOPORT_WRITE;
1300 }
1301#endif
1302#ifdef LOG_ENABLED
1303 RTIOPORT const offPortLog = offPort;
1304 unsigned const cbLog = cb;
1305#endif
1306
1307 /*
1308 * The first register, usually only one is accessed.
1309 */
1310 PDEVSMC pThis = PDMDEVINS_2_DATA(pDevIns, PDEVSMC);
1311 AssertReturn(offPort < RT_ELEMENTS(g_aSmcRegs), VERR_INTERNAL_ERROR_3); /* impossible*/
1312 VBOXSTRICTRC rc = g_aSmcRegs[offPort].pfnWrite(pThis, offPort, u32);
1313
1314 /*
1315 * On the off chance that multiple registers are being read.
1316 */
1317 if (cb > 1)
1318 {
1319 while (cb > 1 && offPort < SMC_REG_COUNT - 1)
1320 {
1321 cb--;
1322 offPort++;
1323 u32 >>= 8;
1324 VBOXSTRICTRC rc2 = g_aSmcRegs[offPort].pfnWrite(pThis, offPort, u32);
1325 if (rc2 != VINF_SUCCESS)
1326 {
1327 if ( rc == VINF_SUCCESS
1328 || (RT_FAILURE(rc2) && RT_SUCCESS(rc))
1329 || (rc2 < rc && RT_SUCCESS(rc2) && RT_SUCCESS(rc)))
1330 rc = rc2;
1331 }
1332 }
1333 }
1334
1335 LogFlow(("smcIoPortWrite: %#04x write access: %#x (LB %u) rc=%Rrc\n", offPortLog, u32, cbLog, VBOXSTRICTRC_VAL(rc) ));
1336 return rc;
1337}
1338
1339
1340/**
1341 * @callback_method_impl{FNIOMIOPORTNEWIN}
1342 */
1343static DECLCALLBACK(VBOXSTRICTRC) smcIoPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
1344{
1345 RT_NOREF1(pvUser);
1346#ifndef IN_RING3
1347 if (cb > 1)
1348 return VINF_IOM_R3_IOPORT_READ;
1349#endif
1350
1351 PDEVSMC pThis = PDMDEVINS_2_DATA(pDevIns, PDEVSMC);
1352#ifdef LOG_ENABLED
1353 RTIOPORT const offPortLog = offPort;
1354 unsigned const cbLog = cb;
1355#endif
1356
1357 /*
1358 * The first register, usually only one is accessed.
1359 */
1360 AssertReturn(offPort < RT_ELEMENTS(g_aSmcRegs), VERR_INTERNAL_ERROR_3); /* impossible*/
1361 Log2(("smcIoPortRead: %#04x read access: LB %u\n", offPort, cb));
1362 uint8_t bValue = 0xff;
1363 VBOXSTRICTRC rc = g_aSmcRegs[offPort].pfnRead(pThis, offPort, &bValue);
1364 *pu32 = bValue;
1365
1366 /*
1367 * On the off chance that multiple registers are being read.
1368 */
1369 if (cb > 1)
1370 {
1371 do
1372 {
1373 cb--;
1374 offPort++;
1375 bValue = 0xff;
1376 if (offPort < SMC_REG_COUNT)
1377 {
1378 VBOXSTRICTRC rc2 = g_aSmcRegs[offPort].pfnRead(pThis, offPort, &bValue);
1379 if (rc2 != VINF_SUCCESS)
1380 {
1381 if ( rc == VINF_SUCCESS
1382 || (RT_FAILURE(rc2) && RT_SUCCESS(rc))
1383 || (rc2 < rc && RT_SUCCESS(rc2) && RT_SUCCESS(rc)))
1384 rc = rc2;
1385 }
1386 }
1387 *pu32 |= (uint32_t)bValue << ((4 - cb) * 8);
1388 } while (cb > 1);
1389 }
1390 LogFlow(("smcIoPortRead: %#04x read access: %#x (LB %u) rc=%Rrc\n", offPortLog, *pu32, cbLog, VBOXSTRICTRC_VAL(rc)));
1391 return rc;
1392}
1393
1394#ifdef IN_RING3
1395
1396/** @callback_method_impl{FNSSMDEVSAVEEXEC} */
1397static DECLCALLBACK(int) smcR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1398{
1399 PDEVSMC pThis = PDMDEVINS_2_DATA(pDevIns, PDEVSMC);
1400 RT_NOREF2(pSSM, pThis);
1401
1402 /** @todo */
1403
1404 return VINF_SUCCESS;
1405}
1406
1407
1408/** @callback_method_impl{FNSSMDEVLOADEXEC} */
1409static DECLCALLBACK(int) smcR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
1410{
1411 PDEVSMC pThis = PDMDEVINS_2_DATA(pDevIns, PDEVSMC);
1412 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
1413 RT_NOREF2(pSSM, pThis);
1414
1415 /* Fend off unsupported versions. */
1416 if ( uVersion != SMC_SAVED_STATE_VERSION
1417#if SMC_SAVED_STATE_VERSION != SMC_SAVED_STATE_VERSION_BAKA
1418 && uVersion != SMC_SAVED_STATE_VERSION_BAKA
1419#endif
1420 && uVersion != SMC_SAVED_STATE_VERSION_BAKA + 1)
1421 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1422
1423 /*
1424 * Do the actual restoring.
1425 */
1426 if (uVersion == SMC_SAVED_STATE_VERSION)
1427 {
1428 /** @todo */
1429 }
1430
1431 return VINF_SUCCESS;
1432}
1433
1434
1435/**
1436 * @interface_method_impl{PDMDEVREG,pfnConstruct}
1437 */
1438static DECLCALLBACK(int) smcR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
1439{
1440 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
1441 PDEVSMC pThis = PDMDEVINS_2_DATA(pDevIns, PDEVSMC);
1442 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
1443
1444 Assert(iInstance == 0); RT_NOREF1(iInstance);
1445
1446 /*
1447 * Init the data.
1448 */
1449 pThis->bDollaryNumber = 1;
1450 pThis->bShutdownReason = 3; /* STOP_CAUSE_POWERKEY_GOOD_CODE */
1451
1452 /*
1453 * Validate configuration.
1454 */
1455 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "DeviceKey|GetKeyFromRealSMC", "");
1456
1457 /*
1458 * Read configuration.
1459 */
1460
1461 /* The DeviceKey sets OSK0 and OSK1. */
1462 int rc = pHlp->pfnCFGMQueryStringDef(pCfg, "DeviceKey", pThis->szOsk0And1, sizeof(pThis->szOsk0And1), "");
1463 if (RT_FAILURE(rc))
1464 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1465 N_("Configuration error: Querying \"DeviceKey\" as a string failed"));
1466
1467 /* Query the key from the OS / real hardware if asked to do so. */
1468 bool fGetKeyFromRealSMC;
1469 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "GetKeyFromRealSMC", &fGetKeyFromRealSMC, false);
1470 if (RT_FAILURE(rc))
1471 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1472 N_("Configuration error: Querying \"GetKeyFromRealSMC\" as a boolean failed"));
1473 if (fGetKeyFromRealSMC)
1474 {
1475# ifdef RT_OS_DARWIN
1476 rc = getSmcKeyOs(pThis->szOsk0And1, sizeof(pThis->szOsk0And1));
1477 if (RT_FAILURE(rc))
1478 {
1479 LogRel(("SMC: Retrieving the SMC key from the OS failed (%Rrc), trying to read it from hardware\n", rc));
1480# endif
1481 rc = PDMDevHlpCallR0(pDevIns, SMC_CALLR0_READ_OSK, 0 /*uArg*/);
1482 if (RT_SUCCESS(rc))
1483 LogRel(("SMC: Successfully retrieved the SMC key from hardware\n"));
1484 else
1485 LogRel(("SMC: Retrieving the SMC key from hardware failed(%Rrc)\n", rc));
1486# ifdef RT_OS_DARWIN
1487 }
1488 else
1489 LogRel(("SMC: Successfully retrieved the SMC key from the OS\n"));
1490# endif
1491 if (RT_FAILURE(rc))
1492 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1493 N_("Failed to query SMC value from the host"));
1494 }
1495
1496 /*
1497 * Register I/O Ports
1498 */
1499 rc = PDMDevHlpIoPortCreateAndMap(pDevIns, SMC_PORT_FIRST, SMC_REG_COUNT, smcIoPortWrite, smcIoPortRead,
1500 "SMC data port", NULL, &pThis->hIoPorts);
1501 AssertRCReturn(rc, rc);
1502
1503 /** @todo Newer versions (2.03) have an MMIO mapping as well (ACPI). */
1504
1505
1506 /*
1507 * Saved state.
1508 */
1509 rc = PDMDevHlpSSMRegister(pDevIns, SMC_SAVED_STATE_VERSION, sizeof(*pThis), smcR3SaveExec, smcR3LoadExec);
1510 if (RT_FAILURE(rc))
1511 return rc;
1512
1513 return VINF_SUCCESS;
1514}
1515
1516#else /* !IN_RING3 */
1517
1518/**
1519 * @callback_method_impl{PDMDEVREGR0,pfnConstruct}
1520 */
1521static DECLCALLBACK(int) smcRZConstruct(PPDMDEVINS pDevIns)
1522{
1523 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
1524 PDEVSMC pThis = PDMDEVINS_2_DATA(pDevIns, PDEVSMC);
1525
1526 int rc = PDMDevHlpIoPortSetUpContext(pDevIns, pThis->hIoPorts, smcIoPortWrite, smcIoPortRead, NULL /*pvUser*/);
1527 AssertRCReturn(rc, rc);
1528 RT_NOREF(pThis);
1529
1530 return VINF_SUCCESS;
1531}
1532
1533#endif /* !IN_RING3 */
1534
1535
1536/**
1537 * The device registration structure.
1538 */
1539const PDMDEVREG g_DeviceSmc =
1540{
1541 /* .u32Version = */ PDM_DEVREG_VERSION,
1542 /* .uReserved0 = */ 0,
1543 /* .szName = */ "smc",
1544 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE,
1545 /* .fClass = */ PDM_DEVREG_CLASS_ARCH,
1546 /* .cMaxInstances = */ 1,
1547 /* .uSharedVersion = */ 42,
1548 /* .cbInstanceShared = */ sizeof(DEVSMC),
1549 /* .cbInstanceCC = */ 0,
1550 /* .cbInstanceRC = */ 0,
1551 /* .cMaxPciDevices = */ 0,
1552 /* .cMaxMsixVectors = */ 0,
1553 /* .pszDescription = */ "Apple System Management Controller",
1554#if defined(IN_RING3)
1555 /* .pszRCMod = */ "VBoxDDRC.rc",
1556 /* .pszR0Mod = */ "VBoxDDR0.r0",
1557 /* .pfnConstruct = */ smcR3Construct,
1558 /* .pfnDestruct = */ NULL,
1559 /* .pfnRelocate = */ NULL,
1560 /* .pfnMemSetup = */ NULL,
1561 /* .pfnPowerOn = */ NULL,
1562 /* .pfnReset = */ NULL,
1563 /* .pfnSuspend = */ NULL,
1564 /* .pfnResume = */ NULL,
1565 /* .pfnAttach = */ NULL,
1566 /* .pfnDetach = */ NULL,
1567 /* .pfnQueryInterface = */ NULL,
1568 /* .pfnInitComplete = */ NULL,
1569 /* .pfnPowerOff = */ NULL,
1570 /* .pfnSoftReset = */ NULL,
1571 /* .pfnReserved0 = */ NULL,
1572 /* .pfnReserved1 = */ NULL,
1573 /* .pfnReserved2 = */ NULL,
1574 /* .pfnReserved3 = */ NULL,
1575 /* .pfnReserved4 = */ NULL,
1576 /* .pfnReserved5 = */ NULL,
1577 /* .pfnReserved6 = */ NULL,
1578 /* .pfnReserved7 = */ NULL,
1579#elif defined(IN_RING0)
1580 /* .pfnEarlyConstruct = */ NULL,
1581 /* .pfnConstruct = */ smcRZConstruct,
1582 /* .pfnDestruct = */ NULL,
1583 /* .pfnFinalDestruct = */ NULL,
1584# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
1585 /* .pfnRequest = */ devR0SmcReqHandler,
1586# else
1587 /* .pfnRequest = */ NULL,
1588# endif
1589 /* .pfnReserved0 = */ NULL,
1590 /* .pfnReserved1 = */ NULL,
1591 /* .pfnReserved2 = */ NULL,
1592 /* .pfnReserved3 = */ NULL,
1593 /* .pfnReserved4 = */ NULL,
1594 /* .pfnReserved5 = */ NULL,
1595 /* .pfnReserved6 = */ NULL,
1596 /* .pfnReserved7 = */ NULL,
1597#elif defined(IN_RC)
1598 /* .pfnConstruct = */ smcRZConstruct,
1599 /* .pfnReserved0 = */ NULL,
1600 /* .pfnReserved1 = */ NULL,
1601 /* .pfnReserved2 = */ NULL,
1602 /* .pfnReserved3 = */ NULL,
1603 /* .pfnReserved4 = */ NULL,
1604 /* .pfnReserved5 = */ NULL,
1605 /* .pfnReserved6 = */ NULL,
1606 /* .pfnReserved7 = */ NULL,
1607#else
1608# error "Not in IN_RING3, IN_RING0 or IN_RC!"
1609#endif
1610 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
1611};
1612
1613#endif /* VBOX_DEVICE_STRUCT_TESTCASE */
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