Changeset 29503 in vbox
- Timestamp:
- May 16, 2010 1:20:10 PM (15 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Additions/common/VBoxService/VBoxServiceCpuHotPlug.cpp
r28800 r29503 41 41 * @{ 42 42 */ 43 # define SYSFS_ACPI_CPU_PATH "/sys/devices /LNXSYSTM:00/device:00"43 # define SYSFS_ACPI_CPU_PATH "/sys/devices" 44 44 # define SYSFS_CPU_PATH "/sys/devices/system/cpu" 45 45 /** @} */ 46 47 /** Path component for the ACPI CPU path. */ 48 typedef struct SYSFSCPUPATHCOMP 49 { 50 /** Flag whether the name is suffixed with a number */ 51 bool fNumberedSuffix; 52 /** Name of the component */ 53 const char *pcszName; 54 } SYSFSCPUPATHCOMP, *PSYSFSCPUPATHCOMP; 55 /** Pointer to a const component. */ 56 typedef const SYSFSCPUPATHCOMP *PCSYSFSCPUPATHCOMP; 57 58 /** 59 * Structure which defines how the entries are assembled. 60 */ 61 typedef struct SYSFSCPUPATH 62 { 63 /** Id when probing for the correct path. */ 64 uint32_t uId; 65 /** Array holding the possible components. */ 66 PCSYSFSCPUPATHCOMP aComponentsPossible; 67 /** Number of entries in the array, excluding the terminator. */ 68 unsigned cComponents; 69 /** Directory handle */ 70 PRTDIR pDir; 71 /** Current directory to try. */ 72 char *pszPath; 73 } SYSFSCPUPATH, *PSYSFSCPUPATH; 74 75 /** Content of uId if the path wasn't probed yet. */ 76 #define ACPI_CPU_PATH_NOT_PROBED UINT32_MAX 77 78 /** Possible combinations of all path components for level 1. */ 79 const SYSFSCPUPATHCOMP g_aAcpiCpuPathLvl1[] = 80 { 81 /** LNXSYSTEM:<id> */ 82 {true, "LNXSYSTM:"} 83 }; 84 85 /** Possible combinations of all path components for level 2. */ 86 const SYSFSCPUPATHCOMP g_aAcpiCpuPathLvl2[] = 87 { 88 /** device:<id> */ 89 {true, "device:"}, 90 /** LNXSYBUS:<id> */ 91 {true, "LNXSYBUS:"} 92 }; 93 94 /** Possible combinations of all path components for level 3 */ 95 const SYSFSCPUPATHCOMP g_aAcpiCpuPathLvl3[] = 96 { 97 /** ACPI0004:<id> */ 98 {true, "ACPI0004:"} 99 }; 100 101 /** Possible combinations of all path components for level 4 */ 102 const SYSFSCPUPATHCOMP g_aAcpiCpuPathLvl4[] = 103 { 104 /** LNXCPU:<id> */ 105 {true, "LNXCPU:"}, 106 /** ACPI_CPU:<id> */ 107 {true, "ACPI_CPU:"} 108 }; 109 110 /** All possible combinations. */ 111 SYSFSCPUPATH g_aAcpiCpuPath[] = 112 { 113 /** Level 1 */ 114 {ACPI_CPU_PATH_NOT_PROBED, g_aAcpiCpuPathLvl1, RT_ELEMENTS(g_aAcpiCpuPathLvl1), NULL, NULL}, 115 /** Level 2 */ 116 {ACPI_CPU_PATH_NOT_PROBED, g_aAcpiCpuPathLvl2, RT_ELEMENTS(g_aAcpiCpuPathLvl2), NULL, NULL}, 117 /** Level 3 */ 118 {ACPI_CPU_PATH_NOT_PROBED, g_aAcpiCpuPathLvl3, RT_ELEMENTS(g_aAcpiCpuPathLvl3), NULL, NULL}, 119 /** Level 4 */ 120 {ACPI_CPU_PATH_NOT_PROBED, g_aAcpiCpuPathLvl4, RT_ELEMENTS(g_aAcpiCpuPathLvl4), NULL, NULL}, 121 }; 46 122 #endif 47 123 48 49 124 #ifdef RT_OS_LINUX 125 /** 126 * Probes for the correct path to the ACPI CPU object in sysfs for the 127 * various different kernel versions and distro's. 128 * 129 * @returns VBox status code. 130 */ 131 static int VBoxServiceCpuHotPlugProbePath(void) 132 { 133 int rc = VINF_SUCCESS; 134 135 /* Probe for the correct path if we didn't already. */ 136 if (RT_UNLIKELY(g_aAcpiCpuPath[0].uId == ACPI_CPU_PATH_NOT_PROBED)) 137 { 138 char *pszPath = NULL; /** < Current path, increasing while we dig deeper. */ 139 140 pszPath = RTStrDup(SYSFS_ACPI_CPU_PATH); 141 if (!pszPath) 142 return VERR_NO_MEMORY; 143 144 /* 145 * Simple algorithm to find the path. 146 * Performance is not a real problem because it is 147 * only executed once. 148 */ 149 for (unsigned iLvlCurr = 0; iLvlCurr < RT_ELEMENTS(g_aAcpiCpuPath); iLvlCurr++) 150 { 151 PSYSFSCPUPATH pAcpiCpuPathLvl = &g_aAcpiCpuPath[iLvlCurr]; 152 153 for (unsigned iCompCurr = 0; iCompCurr < pAcpiCpuPathLvl->cComponents; iCompCurr++) 154 { 155 PCSYSFSCPUPATHCOMP pPathComponent = &pAcpiCpuPathLvl->aComponentsPossible[iCompCurr]; 156 PRTDIR pDirCurr = NULL; 157 char *pszPathTmp = NULL; 158 bool fFound = false; 159 160 rc = RTStrAPrintf(&pszPathTmp, "%s/%s*", pszPath, pPathComponent->pcszName); 161 if (RT_FAILURE(rc)) 162 break; 163 164 /* Open the directory */ 165 rc = RTDirOpenFiltered(&pDirCurr, pszPathTmp, RTDIRFILTER_WINNT); 166 if (RT_FAILURE(rc)) 167 { 168 RTStrFree(pszPathTmp); 169 break; 170 } 171 172 /* Search if the current directory contains one of the possible parts. */ 173 RTDIRENTRY DirFolderContent; 174 while (RT_SUCCESS(RTDirRead(pDirCurr, &DirFolderContent, NULL))) /* Assumption that szName has always enough space */ 175 { 176 if (!strncmp(DirFolderContent.szName, pPathComponent->pcszName, strlen(pPathComponent->pcszName))) 177 { 178 char *pszPathLvl = NULL; 179 180 /* Found, use the complete name to dig deeper. */ 181 fFound = true; 182 pAcpiCpuPathLvl->uId = iCompCurr; 183 rc = RTStrAPrintf(&pszPathLvl, "%s/%s", pszPath, DirFolderContent.szName); 184 185 if (RT_SUCCESS(rc)) 186 { 187 RTStrFree(pszPath); 188 pszPath = pszPathLvl; 189 } 190 break; 191 } 192 } 193 RTDirClose(pDirCurr); 194 195 if (fFound) 196 break; 197 } /* For every possible component. */ 198 199 /* No matching component for this part, no need to continue */ 200 if (RT_FAILURE(rc)) 201 break; 202 } /* For every level */ 203 204 VBoxServiceVerbose(1, "Final path after probing %s rc=%Rrc\n", pszPath, rc); 205 RTStrFree(pszPath); 206 } 207 208 return rc; 209 } 210 50 211 /** 51 212 * Returns the path of the ACPI CPU device with the given core and package ID. … … 58 219 static int VBoxServiceCpuHotPlugGetACPIDevicePath(char **ppszPath, uint32_t idCpuCore, uint32_t idCpuPackage) 59 220 { 60 AssertPtr(ppszPath); 61 62 PRTDIR pDirDevices = NULL; 63 int rc = RTDirOpen(&pDirDevices, SYSFS_ACPI_CPU_PATH); /* could use RTDirOpenFiltered */ 221 int rc = VINF_SUCCESS; 222 223 AssertPtrReturn(ppszPath, VERR_INVALID_PARAMETER); 224 225 rc = VBoxServiceCpuHotPlugProbePath(); 64 226 if (RT_SUCCESS(rc)) 65 227 { 66 /* Search every ACPI0004 container device for LNXCPU devices. */ 67 RTDIRENTRY DirFolderAcpiContainer; 228 /* Build the path from all components. */ 68 229 bool fFound = false; 69 70 while ( RT_SUCCESS(RTDirRead(pDirDevices, &DirFolderAcpiContainer, NULL)) 71 && !fFound) /* Assumption that szName has always enough space */ 230 unsigned iLvlCurr = 0; 231 char *pszPath = NULL; 232 char *pszPathDir = NULL; 233 PSYSFSCPUPATH pAcpiCpuPathLvl = &g_aAcpiCpuPath[iLvlCurr]; 234 235 /* Init everything. */ 236 Assert(pAcpiCpuPathLvl->uId != ACPI_CPU_PATH_NOT_PROBED); 237 rc = RTStrAPrintf(&pszPath, 238 "%s/%s*", SYSFS_ACPI_CPU_PATH, 239 pAcpiCpuPathLvl->aComponentsPossible[pAcpiCpuPathLvl->uId].pcszName); 240 if (RT_FAILURE(rc)) 241 return rc; 242 243 pAcpiCpuPathLvl->pszPath = RTStrDup(SYSFS_ACPI_CPU_PATH); 244 if (!pAcpiCpuPathLvl->pszPath) 245 return VERR_NO_MEMORY; 246 247 /* Open the directory */ 248 rc = RTDirOpenFiltered(&pAcpiCpuPathLvl->pDir, pszPath, RTDIRFILTER_WINNT); 249 if (RT_SUCCESS(rc)) 72 250 { 73 if (!strncmp(DirFolderAcpiContainer.szName, "ACPI0004", 8)) 251 RTStrFree(pszPath); 252 253 /* Search for CPU */ 254 while (!fFound) 74 255 { 75 char *pszAcpiContainerPath = NULL; 76 PRTDIR pDirAcpiContainer = NULL; 77 78 rc = RTStrAPrintf(&pszAcpiContainerPath, "%s/%s", SYSFS_ACPI_CPU_PATH, DirFolderAcpiContainer.szName); 79 if (RT_FAILURE(rc)) 80 break; 81 82 rc = RTDirOpen(&pDirAcpiContainer, pszAcpiContainerPath); 256 /* Get the next directory. */ 257 RTDIRENTRY DirFolderContent; 258 rc = RTDirRead(pAcpiCpuPathLvl->pDir, &DirFolderContent, NULL); 83 259 if (RT_SUCCESS(rc)) 84 260 { 85 RTDIRENTRY DirFolderContent; 86 while (RT_SUCCESS(RTDirRead(pDirAcpiContainer, &DirFolderContent, NULL))) /* Assumption that szName has always enough space */ 261 char *pszPathCurr; 262 263 /* Create the new path. */ 264 rc = RTStrAPrintf(&pszPathCurr, "%s/%s", pAcpiCpuPathLvl->pszPath, DirFolderContent.szName); 265 if (RT_FAILURE(rc)) 266 break; 267 268 /* If this is the last level check for the given core and package id. */ 269 if (iLvlCurr == RT_ELEMENTS(g_aAcpiCpuPath) - 1) 87 270 { 88 if ( !strncmp(DirFolderContent.szName, "LNXCPU", 6) 89 || !strncmp(DirFolderContent.szName, "ACPI_CPU", 8)) 271 /* Get the sysdev */ 272 uint32_t idCore = RTLinuxSysFsReadIntFile(10, "%s/sysdev/topology/core_id", 273 pszPathCurr); 274 uint32_t idPackage = RTLinuxSysFsReadIntFile(10, "%s/sysdev/topology/physical_package_id", 275 pszPathCurr); 276 if ( idCore == idCpuCore 277 && idPackage == idCpuPackage) 90 278 { 91 /* Get the sysdev */ 92 uint32_t idCore = RTLinuxSysFsReadIntFile(10, "%s/%s/sysdev/topology/core_id", 93 pszAcpiContainerPath, DirFolderContent.szName); 94 uint32_t idPackage = RTLinuxSysFsReadIntFile(10, "%s/%s/sysdev/topology/physical_package_id", 95 pszAcpiContainerPath, DirFolderContent.szName); 96 if ( idCore == idCpuCore 97 && idPackage == idCpuPackage) 98 { 99 /* Return the path */ 100 rc = RTStrAPrintf(ppszPath, "%s/%s", pszAcpiContainerPath, DirFolderContent.szName); 101 fFound = true; 102 break; 103 } 279 /* Return the path */ 280 pszPath = pszPathCurr; 281 fFound = true; 282 VBoxServiceVerbose(3, "CPU found\n"); 283 break; 284 } 285 else 286 { 287 /* Get the next directory. */ 288 RTStrFree(pszPathCurr); 289 VBoxServiceVerbose(3, "CPU doesn't match, next directory\n"); 104 290 } 105 291 } 106 107 RTDirClose(pDirAcpiContainer); 292 else 293 { 294 /* Go deeper */ 295 iLvlCurr++; 296 297 VBoxServiceVerbose(3, "Going deeper (iLvlCurr=%u)\n", iLvlCurr); 298 299 pAcpiCpuPathLvl = &g_aAcpiCpuPath[iLvlCurr]; 300 301 Assert(!pAcpiCpuPathLvl->pDir); 302 Assert(!pAcpiCpuPathLvl->pszPath); 303 pAcpiCpuPathLvl->pszPath = pszPathCurr; 304 PCSYSFSCPUPATHCOMP pPathComponent = &pAcpiCpuPathLvl->aComponentsPossible[pAcpiCpuPathLvl->uId]; 305 306 Assert(pAcpiCpuPathLvl->uId != ACPI_CPU_PATH_NOT_PROBED); 307 308 rc = RTStrAPrintf(&pszPathDir, "%s/%s*", pszPathCurr, pPathComponent->pcszName); 309 if (RT_FAILURE(rc)) 310 break; 311 312 VBoxServiceVerbose(3, "New path %s\n", pszPathDir); 313 314 /* Open the directory */ 315 rc = RTDirOpenFiltered(&pAcpiCpuPathLvl->pDir, pszPathDir, RTDIRFILTER_WINNT); 316 if (RT_FAILURE(rc)) 317 break; 318 } 108 319 } 109 110 RTStrFree(pszAcpiContainerPath); 111 } 320 else 321 { 322 /* Go back one level and try to get the next entry. */ 323 Assert(iLvlCurr > 0); 324 325 RTDirClose(pAcpiCpuPathLvl->pDir); 326 RTStrFree(pAcpiCpuPathLvl->pszPath); 327 pAcpiCpuPathLvl->pDir = NULL; 328 pAcpiCpuPathLvl->pszPath = NULL; 329 330 iLvlCurr--; 331 pAcpiCpuPathLvl = &g_aAcpiCpuPath[iLvlCurr]; 332 VBoxServiceVerbose(3, "Directory not found, going back (iLvlCurr=%u)\n", iLvlCurr); 333 } 334 } /* while not found */ 335 } /* Successful init */ 336 337 /* Cleanup */ 338 for (unsigned i = 0; i < RT_ELEMENTS(g_aAcpiCpuPath); i++) 339 { 340 if (g_aAcpiCpuPath[i].pDir) 341 RTDirClose(g_aAcpiCpuPath[i].pDir); 342 if (g_aAcpiCpuPath[i].pszPath) 343 RTStrFree(g_aAcpiCpuPath[i].pszPath); 344 g_aAcpiCpuPath[i].pDir = NULL; 345 g_aAcpiCpuPath[i].pszPath = NULL; 112 346 } 113 114 RTDirClose(pDirDevices); 347 if (pszPathDir) 348 RTStrFree(pszPathDir); 349 if (RT_FAILURE(rc) && pszPath) 350 RTStrFree(pszPath); 351 352 if (RT_SUCCESS(rc)) 353 *ppszPath = pszPath; 115 354 } 116 355
Note:
See TracChangeset
for help on using the changeset viewer.