Changeset 29564 in vbox for trunk/src/VBox/Devices/PC/DevSMC.cpp
- Timestamp:
- May 17, 2010 3:19:33 PM (15 years ago)
- svn:sync-xref-src-repo-rev:
- 61706
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/PC/DevSMC.cpp
r29522 r29564 55 55 #include <VBox/stam.h> 56 56 #include <iprt/assert.h> 57 #ifdef IN_RING0 58 # include <iprt/asm-amd64-x86.h> 59 # include <iprt/once.h> 60 #endif 57 61 #include <iprt/string.h> 58 62 59 63 #include "../Builtins2.h" 60 64 65 66 /******************************************************************************* 67 * Defined Constants And Macros * 68 *******************************************************************************/ 61 69 /* data port used by Apple SMC */ 62 70 #define APPLESMC_DATA_PORT 0x300 … … 71 79 #define APPLESMC_GET_KEY_TYPE_CMD 0x13 72 80 73 static char osk[64];74 75 81 /** The version of the saved state. */ 76 82 #define SMC_SAVED_STATE_VERSION 1 77 83 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 *******************************************************************************/ 78 91 typedef struct AppleSMCData 79 92 { … … 82 95 const char *data; 83 96 } AppleSMCData; 97 98 99 typedef 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 121 static char osk[64]; 84 122 85 123 /* See http://www.mactel-linux.org/wiki/AppleSMC */ … … 95 133 {0, NULL, NULL } 96 134 }; 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). */ 138 static RTONCE g_SmcR0Once = RTONCE_INITIALIZER; 139 /** Indicates whether we've successfully queried the OSK* keys. */ 140 static bool g_fHaveOsk = false; 141 /** The OSK0 value. */ 142 static uint8_t g_abOsk0[32]; 143 /** The OSK1 value. */ 144 static uint8_t g_abOsk1[32]; 145 #endif /* IN_RING0 */ 112 146 113 147 #ifndef VBOX_DEVICE_STRUCT_TESTCASE 114 148 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 */ 158 static 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 */ 181 static 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 */ 241 static 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 */ 253 PDMBOTHCBDECL(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 */ 115 274 #ifdef IN_RING3 275 116 276 /** 117 277 * Saves a state of the SMC device. … … 149 309 /** @todo: implement serialization */ 150 310 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 */164 311 } 165 312 … … 335 482 { 336 483 SMCState *pThis = PDMINS_2_DATA(pDevIns, SMCState *); 337 int rc;338 484 Assert(iInstance == 0); 339 485 … … 346 492 * Validate and read the configuration. 347 493 */ 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)) 368 502 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, 369 503 N_("Configuration error: Querying \"DeviceKey\" as a string failed")); 370 504 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)); 372 538 373 539 /* … … 375 541 */ 376 542 rc = PDMDevHlpIOPortRegister(pDevIns, APPLESMC_DATA_PORT, 1, NULL, 377 378 543 smcIOPortWrite, smcIOPortRead, 544 NULL, NULL, "SMC Data"); 379 545 if (RT_FAILURE(rc)) 380 546 return rc; 381 547 rc = PDMDevHlpIOPortRegister(pDevIns, APPLESMC_CMD_PORT, 1, NULL, 382 383 548 smcIOPortWrite, smcIOPortRead, 549 NULL, NULL, "SMC Commands"); 384 550 if (RT_FAILURE(rc)) 385 551 return rc; … … 399 565 */ 400 566 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-VM410 * 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 }426 567 427 568 return VINF_SUCCESS; … … 444 585 "System Management Controller (SMC) Device", 445 586 /* 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, 447 588 /* fClass */ 448 589 PDM_DEVREG_CLASS_MISC, … … 454 595 smcConstruct, 455 596 /* pfnDestruct */ 456 smcDestruct,597 NULL, 457 598 /* pfnRelocate */ 458 smcRelocate,599 NULL, 459 600 /* pfnIOCtl */ 460 601 NULL,
Note:
See TracChangeset
for help on using the changeset viewer.