VirtualBox

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

Last change on this file since 82331 was 81591, checked in by vboxsync, 5 years ago

Devices: Use PDMDEVINS_2_DATA and PDMDEVINS_2_DATA. bugref:9218

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