VirtualBox

Ignore:
Timestamp:
May 17, 2010 3:19:33 PM (15 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
61706
Message:

updates

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/PC/DevSMC.cpp

    r29522 r29564  
    5555#include <VBox/stam.h>
    5656#include <iprt/assert.h>
     57#ifdef IN_RING0
     58# include <iprt/asm-amd64-x86.h>
     59# include <iprt/once.h>
     60#endif
    5761#include <iprt/string.h>
    5862
    5963#include "../Builtins2.h"
    6064
     65
     66/*******************************************************************************
     67*   Defined Constants And Macros                                               *
     68*******************************************************************************/
    6169/* data port used by Apple SMC */
    6270#define APPLESMC_DATA_PORT      0x300
     
    7179#define APPLESMC_GET_KEY_TYPE_CMD       0x13
    7280
    73 static char osk[64];
    74 
    7581/** The version of the saved state. */
    7682#define SMC_SAVED_STATE_VERSION 1
    7783
     84/** The ring-0 operation number that attempts to get OSK0 and OSK1 from the real
     85 *  SMC. */
     86#define SMC_CALLR0_READ_OSK     1
     87
     88/*******************************************************************************
     89*   Structures and Typedefs                                                    *
     90*******************************************************************************/
    7891typedef struct AppleSMCData
    7992{
     
    8295    const char    *data;
    8396} AppleSMCData;
     97
     98
     99typedef struct
     100{
     101    PPDMDEVINSR3   pDevIns;
     102
     103    uint8_t cmd;
     104    uint8_t status;
     105    uint8_t key[4];
     106    uint8_t read_pos;
     107    uint8_t data_len;
     108    uint8_t data_pos;
     109    uint8_t data[255];
     110
     111    /** The OSK0 value. This is currently only used in the constructor. */
     112    uint8_t abOsk0[32];
     113    /** The OSK1 value. This is currently only used in the constructor */
     114    uint8_t abOsk1[32];
     115} SMCState;
     116
     117/*******************************************************************************
     118*   Global Variables                                                           *
     119*******************************************************************************/
     120#ifdef IN_RING3
     121static char osk[64];
    84122
    85123/* See http://www.mactel-linux.org/wiki/AppleSMC */
     
    95133    {0, NULL,    NULL }
    96134};
    97 
    98 typedef struct
    99 {
    100     PPDMDEVINSR3   pDevIns;
    101 
    102     uint8_t cmd;
    103     uint8_t status;
    104     uint8_t key[4];
    105     uint8_t read_pos;
    106     uint8_t data_len;
    107     uint8_t data_pos;
    108     uint8_t data[255];
    109 
    110     char*    pszDeviceKey;
    111 } SMCState;
     135#endif /* IN_RING3 */
     136#ifdef IN_RING0
     137/** Do once for the SMC ring-0 static data (g_abOsk0, g_abOsk1, g_fHaveOsk).  */
     138static RTONCE   g_SmcR0Once = RTONCE_INITIALIZER;
     139/** Indicates whether we've successfully queried the OSK* keys. */
     140static bool     g_fHaveOsk = false;
     141/** The OSK0 value.   */
     142static uint8_t  g_abOsk0[32];
     143/** The OSK1 value.  */
     144static uint8_t  g_abOsk1[32];
     145#endif /* IN_RING0 */
    112146
    113147#ifndef VBOX_DEVICE_STRUCT_TESTCASE
    114148
     149#ifdef IN_RING0
     150
     151/**
     152 * Waits for the specified status on the host SMC.
     153 *
     154 * @returns success indicator.
     155 * @param   bStatus             The desired status.
     156 * @param   pszWhat             What we're currently doing. For the log.
     157 */
     158static bool devR0SmcWaitHostStatus(uint8_t bStatus, const char *pszWhat)
     159{
     160    uint8_t bCurStatus;
     161    for (uint32_t cMsSleep = 1; cMsSleep <= 64; cMsSleep <<= 1)
     162    {
     163        RTThreadSleep(cMsSleep);
     164        bCurStatus = ASMInU8(APPLESMC_CMD_PORT);
     165        if ((bCurStatus & 0xf) == bStatus)
     166            return true;
     167    }
     168
     169    LogRel(("devR0Smc: %s: bCurStatus=%#x, wanted %#x.\n", pszWhat, bCurStatus, bStatus));
     170    return false;
     171}
     172
     173/**
     174 * Reads a key by name from the host SMC.
     175 *
     176 * @returns success indicator.
     177 * @param   pszName             The key name, must be exactly 4 chars long.
     178 * @param   pbBuf               The output buffer.
     179 * @param   cbBuf               The buffer size. Max 32 bytes.
     180 */
     181static bool devR0SmcQueryHostKey(const char *pszName, uint8_t *pbBuf, size_t cbBuf)
     182{
     183    Assert(strlen(pszName) == 4);
     184    Assert(cbBuf <= 32);
     185    Assert(cbBuf > 0);
     186
     187    /*
     188     * Issue the READ command.
     189     */
     190    uint32_t cMsSleep = 1;
     191    for (;;)
     192    {
     193        ASMOutU8(APPLESMC_CMD_PORT, APPLESMC_READ_CMD);
     194        RTThreadSleep(cMsSleep);
     195        uint8_t bCurStatus = ASMInU8(APPLESMC_CMD_PORT);
     196        if ((bCurStatus & 0xf) == 0xc)
     197            break;
     198        cMsSleep <<= 1;
     199        if (cMsSleep > 64)
     200        {
     201            LogRel(("devR0Smc: %s: bCurStatus=%#x, wanted %#x.\n", "cmd", bCurStatus, 0xc));
     202            return false;
     203        }
     204    }
     205
     206    /*
     207     * Send it the key.
     208     */
     209    for (unsigned off = 0; off < 4; off++)
     210    {
     211        ASMOutU8(APPLESMC_DATA_PORT, pszName[off]);
     212        if (!devR0SmcWaitHostStatus(4, "key"))
     213            return false;
     214    }
     215
     216    /*
     217     * The desired amount of output.
     218     */
     219    ASMOutU8(APPLESMC_DATA_PORT, (uint8_t)cbBuf);
     220
     221    /*
     222     * Read the output.
     223     */
     224    for (size_t off = 0; off < cbBuf; off++)
     225    {
     226        if (!devR0SmcWaitHostStatus(5, off ? "data" : "len"))
     227            return false;
     228        pbBuf[off] = ASMInU8(APPLESMC_DATA_PORT);
     229    }
     230
     231    return true;
     232}
     233
     234/**
     235 * RTOnce callback that initializes g_fHaveOsk, g_abOsk0 and g_abOsk1.
     236 *
     237 * @returns VINF_SUCCESS.
     238 * @param   pvUser1Ignored  Ignored.
     239 * @param   pvUser2Ignored  Ignored.
     240 */
     241static DECLCALLBACK(int) devR0SmcInitOnce(void *pvUser1Ignored, void *pvUser2Ignored)
     242{
     243    g_fHaveOsk = devR0SmcQueryHostKey("OSK0", &g_abOsk0[0], sizeof(g_abOsk0))
     244              && devR0SmcQueryHostKey("OSK1", &g_abOsk1[0], sizeof(g_abOsk1));
     245
     246    NOREF(pvUser1Ignored); NOREF(pvUser2Ignored);
     247    return VINF_SUCCESS;
     248}
     249
     250/**
     251 * @interface_method_impl{FNPDMDEVREQHANDLERR0}
     252 */
     253PDMBOTHCBDECL(int) devR0SmcReqHandler(PPDMDEVINS pDevIns, uint32_t uOperation, uint64_t u64Arg)
     254{
     255    SMCState *pThis = PDMINS_2_DATA(pDevIns, SMCState *);
     256    int       rc    = VERR_INVALID_FUNCTION;
     257
     258    if (uOperation == SMC_CALLR0_READ_OSK)
     259    {
     260        rc = RTOnce(&g_SmcR0Once, devR0SmcInitOnce, NULL, NULL);
     261        if (   RT_SUCCESS(rc)
     262            && g_fHaveOsk)
     263        {
     264            AssertCompile(sizeof(g_abOsk0) == sizeof(pThis->abOsk0));
     265            AssertCompile(sizeof(g_abOsk1) == sizeof(pThis->abOsk1));
     266            memcpy(pThis->abOsk0, g_abOsk0, sizeof(pThis->abOsk0));
     267            memcpy(pThis->abOsk1, g_abOsk1, sizeof(pThis->abOsk1));
     268        }
     269    }
     270    return rc;
     271}
     272
     273#endif /* IN_RING0 */
    115274#ifdef IN_RING3
     275
    116276/**
    117277 * Saves a state of the SMC device.
     
    149309    /** @todo: implement serialization */
    150310    return VINF_SUCCESS;
    151 }
    152 
    153 /**
    154  * Relocation notification.
    155  *
    156  * @returns VBox status.
    157  * @param   pDevIns     The device instance data.
    158  * @param   offDelta    The delta relative to the old address.
    159  */
    160 static DECLCALLBACK(void) smcRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
    161 {
    162     SMCState *pThis = PDMINS_2_DATA(pDevIns, SMCState *);
    163     /* SMC device lives only in R3 now, thus nothing to relocate yet */
    164311}
    165312
     
    335482{
    336483    SMCState   *pThis = PDMINS_2_DATA(pDevIns, SMCState *);
    337     int         rc;
    338484    Assert(iInstance == 0);
    339485
     
    346492     * Validate and read the configuration.
    347493     */
    348     if (!CFGMR3AreValuesValid(pCfg,
    349                               "DeviceKey\0"
    350                               ))
    351         return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
    352                                 N_("Configuration error: Invalid config value(s) for the SMC device"));
    353 
    354     /*
    355      * Query device key
    356      */
    357     rc = CFGMR3QueryStringAlloc(pCfg, "DeviceKey", &pThis->pszDeviceKey);
    358     if (rc == VERR_CFGM_VALUE_NOT_FOUND)
    359     {
    360         pThis->pszDeviceKey = RTStrDup("Invalid");
    361         LogRel(("Invalid SMC device key\n"));
    362         if (!pThis->pszDeviceKey)
    363             return VERR_NO_MEMORY;
    364 
    365         rc = VINF_SUCCESS;
    366     }
    367     else if (RT_FAILURE(rc))
     494    PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "DeviceKey|GetKeyFromRealSMC", "");
     495
     496    /*
     497     * Read the DeviceKey config value.
     498     */
     499    char *pszDeviceKey;
     500    int rc = CFGMR3QueryStringAllocDef(pCfg, "DeviceKey", &pszDeviceKey, "");
     501    if (RT_FAILURE(rc))
    368502        return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
    369503                                   N_("Configuration error: Querying \"DeviceKey\" as a string failed"));
    370504
    371     memcpy(osk, pThis->pszDeviceKey, RTStrNLen(pThis->pszDeviceKey, 64));
     505    size_t cchDeviceKey = strlen(pszDeviceKey);
     506    if (cchDeviceKey > 0)
     507        memcpy(&pThis->abOsk0[0], pszDeviceKey, RT_MIN(cchDeviceKey, sizeof(pThis->abOsk0)));
     508    if (cchDeviceKey > sizeof(pThis->abOsk0))
     509        memcpy(&pThis->abOsk1[0], &pszDeviceKey[sizeof(pThis->abOsk0)],
     510               RT_MIN(cchDeviceKey - sizeof(pThis->abOsk0), sizeof(pThis->abOsk1)));
     511
     512    MMR3HeapFree(pszDeviceKey);
     513
     514    /*
     515     * Query the key from the real hardware if asked to do so.
     516     */
     517    bool fGetKeyFromRealSMC;
     518    rc = CFGMR3QueryBoolDef(pCfg, "GetKeyFromRealSMC", &fGetKeyFromRealSMC, false);
     519    if (RT_FAILURE(rc))
     520        return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
     521                                   N_("Configuration error: Querying \"GetKeyFromRealSMC\" as a boolean failed"));
     522    if (fGetKeyFromRealSMC)
     523    {
     524        rc = PDMDevHlpCallR0(pDevIns, SMC_CALLR0_READ_OSK, 0 /*u64Arg*/);
     525        if (RT_FAILURE(rc))
     526            return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
     527                                       N_("Failed to query SMC value from the host"));
     528    }
     529
     530    /*
     531     * For practical/historical reasons, the OSK[0|1] data is stored in a
     532     * global buffer in ring-3.
     533     */
     534    AssertCompile(sizeof(osk) == sizeof(pThis->abOsk0) + sizeof(pThis->abOsk1));
     535    AssertCompile(sizeof(char) == sizeof(uint8_t));
     536    memcpy(osk, pThis->abOsk0, sizeof(pThis->abOsk0));
     537    memcpy(&osk[sizeof(pThis->abOsk0)], pThis->abOsk1, sizeof(pThis->abOsk1));
    372538
    373539    /*
     
    375541     */
    376542    rc = PDMDevHlpIOPortRegister(pDevIns, APPLESMC_DATA_PORT, 1, NULL,
    377                                   smcIOPortWrite, smcIOPortRead,
    378                                   NULL, NULL, "SMC Data");
     543                                 smcIOPortWrite, smcIOPortRead,
     544                                 NULL, NULL, "SMC Data");
    379545    if (RT_FAILURE(rc))
    380546        return rc;
    381547    rc = PDMDevHlpIOPortRegister(pDevIns, APPLESMC_CMD_PORT, 1, NULL,
    382                                   smcIOPortWrite, smcIOPortRead,
    383                                   NULL, NULL, "SMC Commands");
     548                                 smcIOPortWrite, smcIOPortRead,
     549                                 NULL, NULL, "SMC Commands");
    384550    if (RT_FAILURE(rc))
    385551        return rc;
     
    399565     */
    400566    PDMDevHlpDBGFInfoRegister(pDevIns, "smc", "Display SMC status. (no arguments)", smcInfo);
    401 
    402     return VINF_SUCCESS;
    403 }
    404 
    405 
    406 /**
    407  * Destruct a device instance.
    408  *
    409  * Most VM resources are freed by the VM. This callback is provided so that any non-VM
    410  * resources can be freed correctly.
    411  *
    412  * @param   pDevIns     The device instance data.
    413  */
    414 static DECLCALLBACK(int) smcDestruct(PPDMDEVINS pDevIns)
    415 {
    416     SMCState*  pThis = PDMINS_2_DATA(pDevIns, SMCState*);
    417 
    418     /*
    419      * Free MM heap pointers.
    420      */
    421     if (pThis->pszDeviceKey)
    422     {
    423         MMR3HeapFree(pThis->pszDeviceKey);
    424         pThis->pszDeviceKey = NULL;
    425     }
    426567
    427568    return VINF_SUCCESS;
     
    444585    "System Management Controller (SMC) Device",
    445586    /* fFlags */
    446     PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_32_64 | PDM_DEVREG_FLAGS_PAE36,
     587    PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_32_64 | PDM_DEVREG_FLAGS_PAE36| PDM_DEVREG_FLAGS_R0,
    447588    /* fClass */
    448589    PDM_DEVREG_CLASS_MISC,
     
    454595    smcConstruct,
    455596    /* pfnDestruct */
    456     smcDestruct,
     597    NULL,
    457598    /* pfnRelocate */
    458     smcRelocate,
     599    NULL,
    459600    /* pfnIOCtl */
    460601    NULL,
Note: See TracChangeset for help on using the changeset viewer.

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