/* $Id$ */
/** @file
* DevSmc - Apple System Manaagement Controller.
*
* The SMC is controlling power, fans, take measurements (voltage, temperature,
* fan speed, ++), and lock Mac OS X to Apple hardware. For more details see:
*/
/*
* Copyright (C) 2013-2014 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#ifdef IN_RING0
# include <iprt/asm-amd64-x86.h>
#endif
#include "VBoxDD.h"
/*******************************************************************************
* Defined Constants And Macros *
*******************************************************************************/
/** The current version of the saved state. */
/** Empty saved state version. */
/** The ring-0 operation number that attempts to get OSK0 and OSK1 from the real
* SMC. */
/** @name Apple SMC port and register definitions.
* @{ */
/** The first Apple SMC port. */
/** The number of registers (also ports). */
/** The data register. */
/** The command register. */
/** Status code register. */
/** @} */
/** @name Apple SMC Commands.
* @{ */
/** @} */
/** @name Apple SMC Status Codes.
* @{ */
/** @} */
/** @name Apple SMC Key Attributes.
* @{ */
/** @} */
/** The index of the first enumerable key in g_aSmcKeys. */
/** Macro for emitting a static DEVSMC4CHID initializer. */
/**
* Macro for comparing DEVSMC4CHID with a string value.
* @returns true if equal, false if not.
*/
#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]) )
/** Indicates the we want a 2.x SMC. */
#define VBOX_WITH_SMC_2_x
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
/**
* 4 char identifier
*/
typedef union DEVSMC4CHID
{
/** Byte view. */
/** 32-bit unsigned integer view. */
} DEVSMC4CHID;
/**
* Current key data area for communicating with the guest.
*/
typedef struct DEVSMCCURKEY
{
/** The key. */
/** The data type. */
/** Key attributes. */
/** The value length. */
/**
* The value union. 32 bytes is probably sufficient here, but we provide a
* little more room since it doesn't cost us anything. */
union
{
/** Byte view. */
/** 16-bit view. */
/** 32-bit view. */
} Value;
} DEVSMCCURKEY;
/** Pointer to the current key buffer. */
/** Const pointer to the current key buffer. */
/**
* The device
*/
typedef struct DEVSMC
{
/** The current command (SMC_PORT_CMD write). */
/** Current key offset. */
/** Current value offset. */
/** Number of keys in the aKeys array. */
/** The current key data the user is accessing. */
/**
*
* The DATA register entry is not used at all. The CMD register entry contains
* the state value.
*/
union
{
/** Index register view. */
/** Named register view. */
struct
{
/** The current state (SMC_PORT_CMD read). */
/** The current status code (SMC_PORT_STATUS_CODE). */
} s;
} u;
/** @name Key data.
* @{ */
/** OSK0 and OSK1. */
/** $Num - unknown function. */
/** MSSD - shutdown reason. */
/** NATJ - Ninja action timer job. */
/** @} */
} DEVSMC;
#ifndef _MSC_VER
#endif
/** Pointer to the SMC state. */
#ifndef VBOX_DEVICE_STRUCT_TESTCASE
/**
*
* @returns Apple SMC Status Code.
* @param pThis The SMC instance data.
* @param pCurKey The current key structure (input / output).
* @param bCmd The current command (mostly for getters that also
* provides attributes or type info).
* @param pKeyDesc Pointer to the key descriptor so that the getter can
* service more than once key.
*/
struct DEVSMCKEYDESC const *pKeyDesc);
/**
* Method for setting the key value.
*
* @returns Apple SMC Status Code.
* @param pThis The SMC instance data.
* @param pCurKey The current key structure (input / output).
* @param bCmd The current command (currently not relevant).
* @param pKeyDesc Pointer to the key descriptor so that the getter can
* service more than once key.
*/
struct DEVSMCKEYDESC const *pKeyDesc);
/**
* Key descriptor.
*/
typedef struct DEVSMCKEYDESC
{
/** The key 4 character identifier. */
/** Type 4 character identifier. 0 means the getter will set it dynamically. */
/** Getter method, see DEVSMCKEYPUTTER. */
/** Putter method, see DEVSMCKEYPUTTER. */
/** Attributes. 0 means the getter will set it dynamically. */
/** Pointer to a constant SMC key descriptor. */
/*******************************************************************************
* Internal Functions *
*******************************************************************************/
#ifdef IN_RING3
# ifdef VBOX_WITH_SMC_2_x
# endif
#endif
/*******************************************************************************
* Global Variables *
*******************************************************************************/
#ifdef IN_RING3
/**
* Apple SMC key descriptor table.
*/
{
/* Non-enum keys first. */
{ SMC4CH("OSK0"), SMC4CH("ch8*"), scmKeyGetOSKs, NULL, 32, SMC_KEY_ATTR_READ | SMC_KEY_ATTR_FUNCTION },
{ SMC4CH("OSK1"), SMC4CH("ch8*"), scmKeyGetOSKs, NULL, 32, SMC_KEY_ATTR_READ | SMC_KEY_ATTR_FUNCTION },
/* The first enum key is the #KEY value. */
# ifdef VBOX_WITH_SMC_2_x
{ SMC4CH("$Num"), SMC4CH("ui8 "), scmKeyGetDollarNumber, scmKeyPutDollarNumber, 1, SMC_KEY_ATTR_READ | SMC_KEY_ATTR_WRITE | SMC_KEY_ATTR_PRIVATE },
# else
# endif
{ SMC4CH("MSSD"), SMC4CH("si8 "), scmKeyGetShutdownReason, scmKeyPutShutdownReason, 1, SMC_KEY_ATTR_READ | SMC_KEY_ATTR_WRITE | SMC_KEY_ATTR_PRIVATE },
/* MSDS is not present on MacPro3,1 nor MacBookPro10,1, so returning not found is fine. */
# ifdef VBOX_WITH_SMC_2_x
# endif
{ SMC4CH("NATJ"), SMC4CH("ui8 "), scmKeyGetNinjaTimerAction, scmKeyPutNinjaTimerAction, 1, SMC_KEY_ATTR_READ | SMC_KEY_ATTR_WRITE | SMC_KEY_ATTR_PRIVATE },
/** @todo MSSP, NTOK and more. */
};
#endif
#ifdef IN_RING0
/** Do once for the SMC ring-0 static data (g_abOsk0And1, g_fHaveOsk). */
/** Indicates whether we've successfully queried the OSK* keys. */
static bool g_fHaveOsk = false;
/** The OSK0 and OSK1 values. */
/**
* Waits for the specified state on the host SMC.
*
* @returns success indicator.
* @param bState The desired state.
* @param pszWhat What we're currently doing. For the log.
*/
{
{
return true;
}
#if 0
LogRel(("SMC: status2=%#x status3=%#x w=%#x dw=%#x\n", bCurStatus2, bCurStatus3, wCurStatus3, dwCurStatus3));
#endif
return false;
}
/**
* Reads a key by name from the host SMC.
*
* @returns success indicator.
* @param pszName The key name, must be exactly 4 chars long.
* @param pbBuf The output buffer.
* @param cbBuf The buffer size. Max 32 bytes.
*/
{
/*
* Issue the READ command.
*/
for (;;)
{
break;
cMsSleep <<= 1;
if (cMsSleep > 64)
{
return false;
}
}
/*
* Send it the key.
*/
{
return false;
}
/*
* The desired amount of output.
*/
/*
* Read the output.
*/
{
return false;
}
return true;
}
/**
* RTOnce callback that initializes g_fHaveOsk and g_abOsk0And1.
*
* @returns VINF_SUCCESS.
* @param pvUserIgnored Ignored.
*/
{
#if 0
/*
* Dump the device registers.
*/
#endif
return VINF_SUCCESS;
}
/**
* @callback_method_impl{FNPDMDEVREQHANDLERR0}
*/
{
if (uOperation == SMC_CALLR0_READ_OSK)
{
if ( RT_SUCCESS(rc)
&& g_fHaveOsk)
{
}
}
return rc;
}
#endif /* IN_RING0 */
#ifdef IN_RING3 /* For now. */
/** @callback_method_impl{DEVSMCKEYGETTER, OSK0 and OSK1} */
static uint8_t scmKeyGetOSKs(PDEVSMC pThis, PDEVSMCCURKEY pCurKey, uint8_t bCmd, PCDEVSMCKEYDESC pKeyDesc)
{
pszSrc += 32;
return SMC_STATUS_CD_SUCCESS;
}
/** @callback_method_impl{DEVSMCKEYGETTER, \#KEY} */
static uint8_t scmKeyGetKeyCount(PDEVSMC pThis, PDEVSMCCURKEY pCurKey, uint8_t bCmd, PCDEVSMCKEYDESC pKeyDesc)
{
return SMC_STATUS_CD_SUCCESS;
}
/** @callback_method_impl{DEVSMCKEYGETTER, REV - Source revision.} */
static uint8_t scmKeyGetRevision(PDEVSMC pThis, PDEVSMCCURKEY pCurKey, uint8_t bCmd, PCDEVSMCKEYDESC pKeyDesc)
{
#ifdef VBOX_WITH_SMC_2_x
#else
#endif
return SMC_STATUS_CD_SUCCESS;
}
#ifdef VBOX_WITH_SMC_2_x
/** @callback_method_impl{DEVSMCKEYGETTER, $Adr - SMC address.} */
static uint8_t scmKeyGetDollarAddress(PDEVSMC pThis, PDEVSMCCURKEY pCurKey, uint8_t bCmd, PCDEVSMCKEYDESC pKeyDesc)
{
return VINF_SUCCESS;
}
/** @callback_method_impl{DEVSMCKEYGETTER, $Num - Some kind of number.} */
static uint8_t scmKeyGetDollarNumber(PDEVSMC pThis, PDEVSMCCURKEY pCurKey, uint8_t bCmd, PCDEVSMCKEYDESC pKeyDesc)
{
return VINF_SUCCESS;
}
/** @callback_method_impl{DEVSMCKEYPUTTER, $Num - Some kind of number.} */
static uint8_t scmKeyPutDollarNumber(PDEVSMC pThis, PCDEVSMCCURKEY pCurKey, uint8_t bCmd, PCDEVSMCKEYDESC pKeyDesc)
{
return VINF_SUCCESS;
}
#endif /* VBOX_WITH_SMC_2_x */
/** @callback_method_impl{DEVSMCKEYGETTER, MSSD - Machine Shutdown reason.} */
static uint8_t scmKeyGetShutdownReason(PDEVSMC pThis, PDEVSMCCURKEY pCurKey, uint8_t bCmd, PCDEVSMCKEYDESC pKeyDesc)
{
return SMC_STATUS_CD_SUCCESS;
}
/** @callback_method_impl{DEVSMCKEYPUTTER, MSSD - Machine Shutdown reason.} */
static uint8_t scmKeyPutShutdownReason(PDEVSMC pThis, PCDEVSMCCURKEY pCurKey, uint8_t bCmd, PCDEVSMCKEYDESC pKeyDesc)
{
return SMC_STATUS_CD_SUCCESS;
}
/** @callback_method_impl{DEVSMCKEYGETTER, MSSD - Ninja timer action job.} */
static uint8_t scmKeyGetNinjaTimerAction(PDEVSMC pThis, PDEVSMCCURKEY pCurKey, uint8_t bCmd, PCDEVSMCKEYDESC pKeyDesc)
{
return SMC_STATUS_CD_SUCCESS;
}
/** @callback_method_impl{DEVSMCKEYPUTTER, NATJ - Ninja timer action job.} */
static uint8_t scmKeyPutNinjaTimerAction(PDEVSMC pThis, PCDEVSMCCURKEY pCurKey, uint8_t bCmd, PCDEVSMCKEYDESC pKeyDesc)
{
Log(("scmKeyPutNinjaTimerAction: %#x -> %#x\n", pThis->bNinjaActionTimerJob, pCurKey->Value.ab[0]));
return SMC_STATUS_CD_SUCCESS;
}
#ifdef VBOX_WITH_SMC_2_x
/** @callback_method_impl{DEVSMCKEYGETTER, Generic one getter.} */
static uint8_t scmKeyGetOne(PDEVSMC pThis, PDEVSMCCURKEY pCurKey, uint8_t bCmd, PCDEVSMCKEYDESC pKeyDesc)
{
return SMC_STATUS_CD_SUCCESS;
}
#endif /* VBOX_WITH_SMC_2_x */
/** @callback_method_impl{DEVSMCKEYGETTER, Generic zero getter.} */
static uint8_t scmKeyGetZero(PDEVSMC pThis, PDEVSMCCURKEY pCurKey, uint8_t bCmd, PCDEVSMCKEYDESC pKeyDesc)
{
return SMC_STATUS_CD_SUCCESS;
}
/**
* Looks up a key and copies its value and attributes into the CurKey.
*
* @returns Key index on success, UINT32_MAX on failure.
* @param pThis The SMC instance data.
* @param uKeyValue The key value (DEVSMC4CHID.u32).
*/
{
while (iKey-- > 0)
return iKey;
return UINT32_MAX;
}
/**
* Looks up a key and copies its value and attributes into the CurKey.
*
* @returns Apple SMC Status Code.
* @param pThis The SMC instance data.
*/
{
#ifdef LOG_ENABLED
#endif
if (iKey != UINT32_MAX)
{
{
{
if (bRc == SMC_STATUS_CD_SUCCESS)
{
LogFlow(("smcKeyGetByName: key=%4.4s value=%.*Rhxs\n",
return SMC_STATUS_CD_SUCCESS;
}
}
else
{
}
}
else
{
Log(("smcKeyGetByName: Wrong value size; user=%#x smc=%#x key=%4.4s !\n",
}
}
else
{
Log(("smcKeyGetByName: Key not found! key=%4.4s size=%#x\n", &uKeyValueLog, pThis->CurKey.cbValue));
}
return bRc;
}
/**
* Looks up a key by index and copies its name (and attributes) into the CurKey.
*
* @returns Apple SMC Status Code.
* @param pThis The SMC instance data.
*/
{
{
pThis->CurKey.Key.ab[3], pThis->CurKey.Key.ab[2], pThis->CurKey.Key.ab[1], pThis->CurKey.Key.ab[0]));
}
else
{
Log(("smcKeyGetByIndex: Key out or range: %#x, max %#x\n", iKey, RT_ELEMENTS(g_aSmcKeys) - SMC_KEYIDX_FIRST_ENUM));
}
return bRc;
}
/**
* Looks up a key by index and copies its attributes into the CurKey.
*
* @returns Apple SMC Status Code.
* @param pThis The SMC instance data.
*/
{
#ifdef LOG_ENABLED
#endif
if (iKey != UINT32_MAX)
{
else
if (bRc == SMC_STATUS_CD_SUCCESS)
{
LogFlow(("smcKeyGetAttrByName: key=%4.4s value=%.*Rhxs\n",
return SMC_STATUS_CD_SUCCESS;
}
}
else
{
Log(("smcKeyGetAttrByName: Key not found! key=%4.4s size=%#x\n", &uKeyValueLog, pThis->CurKey.cbValue));
}
return bRc;
}
{
return 0;
}
{
return 0;
}
/**
* Data register read.
*
* @returns VINF_SUCCESS or VINF_IOM_R3_IOPORT_WRITE.
* @param uReg The register number.
* @param pbValue Where to return the value.
*/
{
{
case SMC_CMD_GET_KEY_VALUE:
{
}
else
{
Log(("smcRegData_r: Reading too much or at wrong time during SMC_CMD_GET_KEY_INFO! bState=%#x offValue=%#x\n",
}
break;
case SMC_CMD_GET_KEY_INFO:
{
else
}
else
{
Log(("smcRegData_r: Reading too much or at wrong time during SMC_CMD_GET_KEY_INFO! bState=%#x offValue=%#x\n",
}
break;
case SMC_CMD_GET_KEY_BY_INDEX:
{
}
else
{
Log(("smcRegData_r: Reading too much or at wrong time during GET_KEY_BY_INDEX! bState=%#x offValue=%#x\n",
}
break;
case SMC_CMD_PUT_KEY:
Log(("smcRegData_r: Attempting to read data during PUT_KEY!\n"));
*pbValue = 0xff;
break;
default:
Log(("smcRegData_r: Unknown command attempts reading data\n"));
*pbValue = 0xff;
break;
}
return VINF_SUCCESS;
}
/**
* Data register write.
*
* @returns VINF_SUCCESS or VINF_IOM_R3_IOPORT_WRITE.
* @param uReg The register number.
* @param bValue The value being written.
*/
{
{
/*
* Get or put key value.
*
* 5 bytes written, first 4 is the key the 5th is the value size. In
* the case of a put the value bytes are then written, while a get will
* read the value bytes.
*/
case SMC_CMD_GET_KEY_VALUE:
case SMC_CMD_PUT_KEY:
{
/* Key byte. */
}
{
/* Data length. */
{
else
}
else
{
}
}
{
/* More value bytes for put key action. */
else
{
}
}
else
{
Log(("smcRegData_w: Writing too much data on %s command!\n", pThis->bCmd == SMC_CMD_PUT_KEY ? "put" : "get"));
}
break;
/*
* Get key info and key by index seems to take action after the last
* key char is written. They then both go into a data reading phase.
*/
case SMC_CMD_GET_KEY_INFO:
case SMC_CMD_GET_KEY_BY_INDEX:
{
{
else
}
else
{
}
}
else
{
Log(("smcRegData_w: Writing data beyond 5th byte on get %s command!\n",
}
break;
default:
break;
}
return VINF_SUCCESS;
}
/**
* Command register write.
*
* @returns VINF_SUCCESS or VINF_IOM_R3_IOPORT_WRITE.
* @param uReg The register number.
* @param bValue The value being written.
*/
{
/* Validate the command. */
switch (bValue)
{
case SMC_CMD_GET_KEY_VALUE:
case SMC_CMD_PUT_KEY:
case SMC_CMD_GET_KEY_BY_INDEX:
case SMC_CMD_GET_KEY_INFO:
break;
default:
break;
}
return VINF_SUCCESS;
}
/**
* Generic register write.
*
* @returns VINF_SUCCESS or VINF_IOM_R3_IOPORT_WRITE.
* @param uReg The register number.
* @param bValue The value being written.
*/
{
return VINF_SUCCESS;
}
/**
* Read from register that isn't writable and reads as 0xFF.
*
* @returns VINF_SUCCESS or VINF_IOM_R3_IOPORT_WRITE.
* @param uReg The register number.
* @param pbValue Where to return the value.
*/
{
return VINF_SUCCESS;
}
/**
* Write to register that isn't writable and reads as 0xFF.
*
* @returns VINF_SUCCESS or VINF_IOM_R3_IOPORT_WRITE.
* @param uReg The register number.
* @param bValue The value being written.
*/
{
return VINF_SUCCESS;
}
/**
* Read from register that isn't writable and reads as 0xFF.
*
* @returns VINF_SUCCESS or VINF_IOM_R3_IOPORT_WRITE.
* @param uReg The register number.
* @param pbValue Where to return the value.
*/
{
*pbValue = 0xff;
return VINF_SUCCESS;
}
/**
* SMC register handlers (indexed by relative I/O port).
*
* The device seems to be all byte registers and will split wider
* accesses between registers like if it was MMIO. To better illustrate it
* here is the output of the code in devR0SmcInitOnce on a MacPro3,1:
* @verbatim
* SMC: 0x0300=0xffffff63 w={0xff63, 0xffff}, b={0x63 0xff 0xff 0xff}
* SMC: 0x0301=0x0cffffff w={0xffff, 0x0cff}, b={0xff 0xff 0xff 0x0c}
* SMC: 0x0302=0xff0cffff w={0xffff, 0xff0c}, b={0xff 0xff 0x0c 0xff}
* SMC: 0x0303=0xffff0cff w={0x0cff, 0xffff}, b={0xff 0x0c 0xff 0xff}
* SMC: 0x0304=0xffffff0c w={0xff0c, 0xffff}, b={0x0c 0xff 0xff 0xff}
* SMC: 0x0305=0xffffffff w={0xffff, 0xffff}, b={0xff 0xff 0xff 0xff}
* SMC: 0x0306=0xffffffff w={0xffff, 0xffff}, b={0xff 0xff 0xff 0xff}
* SMC: 0x0307=0xffffffff w={0xffff, 0xffff}, b={0xff 0xff 0xff 0xff}
* SMC: 0x0308=0xffffffff w={0xffff, 0xffff}, b={0xff 0xff 0xff 0xff}
* SMC: 0x0309=0xffffffff w={0xffff, 0xffff}, b={0xff 0xff 0xff 0xff}
* SMC: 0x030a=0xffffffff w={0xffff, 0xffff}, b={0xff 0xff 0xff 0xff}
* SMC: 0x030b=0xffffffff w={0xffff, 0xffff}, b={0xff 0xff 0xff 0xff}
* SMC: 0x030c=0xffffffff w={0xffff, 0xffff}, b={0xff 0xff 0xff 0xff}
* SMC: 0x030d=0x00ffffff w={0xffff, 0x00ff}, b={0xff 0xff 0xff 0x00}
* SMC: 0x030e=0x0000ffff w={0xffff, 0x0000}, b={0xff 0xff 0x00 0x00}
* SMC: 0x030f=0x000000ff w={0x00ff, 0x0000}, b={0xff 0x00 0x00 0x00}
* SMC: 0x0310=0x00000000 w={0x0000, 0x0000}, b={0x00 0x00 0x00 0x00}
* SMC: 0x0311=0x00000000 w={0x0000, 0x0000}, b={0x00 0x00 0x00 0x00}
* SMC: 0x0312=0x00000000 w={0x0000, 0x0000}, b={0x00 0x00 0x00 0x00}
* SMC: 0x0313=0x00000000 w={0x0000, 0x0000}, b={0x00 0x00 0x00 0x00}
* SMC: 0x0314=0x00000000 w={0x0000, 0x0000}, b={0x00 0x00 0x00 0x00}
* SMC: 0x0315=0x00000000 w={0x0000, 0x0000}, b={0x00 0x00 0x00 0x00}
* SMC: 0x0316=0x00000000 w={0x0000, 0x0000}, b={0x00 0x00 0x00 0x00}
* SMC: 0x0317=0x00000000 w={0x0000, 0x0000}, b={0x00 0x00 0x00 0x00}
* SMC: 0x0318=0x00000000 w={0x0000, 0x0000}, b={0x00 0x00 0x00 0x00}
* SMC: 0x0319=0xbe000000 w={0x0000, 0xbe00}, b={0x00 0x00 0x00 0xbe}
* SMC: 0x031a=0xbabe0000 w={0x0000, 0xbabe}, b={0x00 0x00 0xbe 0xba}
* SMC: 0x031b=0x00babe00 w={0xbe00, 0x00ba}, b={0x00 0xbe 0xba 0x00}
* SMC: 0x031c=0xbe00babe w={0xbabe, 0xbe00}, b={0xbe 0xba 0x00 0xbe}
* SMC: 0x031d=0xffbe00ba w={0x00ba, 0xffbe}, b={0xba 0x00 0xbe 0xff}
* SMC: 0x031e=0xffffbe00 w={0xbe00, 0xffff}, b={0x00 0xbe 0xff 0xff}
* SMC: 0x031f=0xffffffbe w={0xffbe, 0xffff}, b={0xbe 0xff 0xff 0xff}
* @endverbatim
*
* The last dword is writable (0xbeXXbabe) where in the register at 0x1e is some
* kind of status register for qualifying search failures and the like and will
* be cleared under certain conditions. The whole dword can be written and read
* back unchanged, according to my experiments. The 0x00 and 0x04 registers
* does not read back what is written.
*
* My guess is that the 0xff values indicates ports that are not writable and
* hardwired to 0xff, while the other values indicates ports that can be written
* to and normally read back as written. I'm not going to push my luck too far
* wrt to exact behavior until I see the guest using the registers.
*/
static const struct
{
{
};
/** @callback_method_impl{FNIOMIOPORTOUT} */
PDMBOTHCBDECL(int) smcIoPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
{
#ifndef IN_RING3
if (cb > 1)
return VINF_IOM_R3_IOPORT_WRITE;
#endif
/*
* The first register, usually only one is accessed.
*/
/*
* On the off chance that multiple registers are being read.
*/
if (cb > 1)
{
{
cb--;
uReg++;
u32 >>= 8;
if (rc2 != VINF_SUCCESS)
{
if ( rc == VINF_SUCCESS
}
}
}
return rc;
}
/** @callback_method_impl{FNIOMIOPORTIN} */
PDMBOTHCBDECL(int) smcIoPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
{
#ifndef IN_RING3
if (cb > 1)
return VINF_IOM_R3_IOPORT_READ;
#endif
/*
* The first register, usually only one is accessed.
*/
/*
* On the off chance that multiple registers are being read.
*/
if (cb > 1)
{
do
{
cb--;
uReg++;
bValue = 0xff;
if (uReg < SMC_REG_COUNT)
{
if (rc2 != VINF_SUCCESS)
{
if ( rc == VINF_SUCCESS
}
}
} while (cb > 1);
}
return rc;
}
#endif /* IN_RING3 for now */
#ifdef IN_RING3
/** @callback_method_impl{FNSSMDEVSAVEEXEC} */
{
/** @todo */
return VINF_SUCCESS;
}
/** @callback_method_impl{FNSSMDEVLOADEXEC} */
static DECLCALLBACK(int) smcLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
{
/* Fend off unsupported versions. */
if ( uVersion != SMC_SAVED_STATE_VERSION
/*
* Do the actual restoring.
*/
if (uVersion == SMC_SAVED_STATE_VERSION)
{
/** @todo */
}
return VINF_SUCCESS;
}
/**
* @interface_method_impl{PDMDEVREG,pfnConstruct}
*/
{
/*
* Init the data.
*/
/*
* Validate configuration.
*/
/*
* Read configuration.
*/
/* The DeviceKey sets OSK0 and OSK1. */
if (RT_FAILURE(rc))
N_("Configuration error: Querying \"DeviceKey\" as a string failed"));
/* Query the key from the real hardware if asked to do so. */
bool fGetKeyFromRealSMC;
if (RT_FAILURE(rc))
N_("Configuration error: Querying \"GetKeyFromRealSMC\" as a boolean failed"));
if (fGetKeyFromRealSMC)
{
if (RT_FAILURE(rc))
N_("Failed to query SMC value from the host"));
}
/*
* Register I/O Ports
*/
/** @todo Newer versions (2.03) have an MMIO mapping as well (ACPI). */
/*
* Saved state.
*/
rc = PDMDevHlpSSMRegister(pDevIns, SMC_SAVED_STATE_VERSION, sizeof(*pThis), smcSaveExec, smcLoadExec);
if (RT_FAILURE(rc))
return rc;
return VINF_SUCCESS;
}
/**
* The device registration structure.
*/
{
/* u32Version */
/* szName */
"smc",
/* szRCMod */
"VBoxDDGC.gc",
/* szR0Mod */
"VBoxDDR0.r0",
/* pszDescription */
"Apple System Management Controller",
/* fFlags */
PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_DEFAULT | PDM_DEVREG_FLAGS_R0 | PDM_DEVREG_FLAGS_RC,
/* fClass */
/* cMaxInstances */
1,
/* cbInstance */
sizeof(DEVSMC),
/* pfnConstruct */
/* pfnDestruct */
NULL,
/* pfnRelocate */
NULL,
/* pfnMemSetup */
NULL,
/* pfnPowerOn */
NULL,
/* pfnReset */
NULL,
/* pfnSuspend */
NULL,
/* pfnResume */
NULL,
/* pfnAttach */
NULL,
/* pfnDetach */
NULL,
/* pfnQueryInterface. */
NULL,
/* pfnInitComplete. */
NULL,
/* pfnPowerOff */
NULL,
/* pfnSoftReset */
NULL,
/* u32VersionEnd */
};
#endif /* IN_RING3 */
#endif /* VBOX_DEVICE_STRUCT_TESTCASE */