Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1643 lines
51 KiB

  1. /*++
  2. Copyright (c) 1997-1999 Microsoft Corporation
  3. Module Name:
  4. smbios.c.c
  5. Abstract:
  6. SMBIOS interface for WMI
  7. Author:
  8. AlanWar
  9. Environment:
  10. Kernel mode
  11. Revision History:
  12. --*/
  13. #if defined(_AMD64_) || defined(_IA64_) || defined(i386)
  14. #include "wmikmp.h"
  15. #include "arc.h"
  16. #include "smbios.h"
  17. void WmipGetSMBiosFromLoaderBlock(
  18. PVOID LoaderBlockPtr
  19. );
  20. NTSTATUS WmipSMBiosDataRegQueryRoutine(
  21. IN PWSTR ValueName,
  22. IN ULONG ValueType,
  23. IN PVOID ValueData,
  24. IN ULONG ValueLength,
  25. IN PVOID Context,
  26. IN PVOID EntryContext
  27. );
  28. BOOLEAN WmipIsSMBiosKey(
  29. HANDLE ParentKeyHandle,
  30. PWCHAR KeyName,
  31. PUCHAR *SMBiosTableVirtualAddress,
  32. PULONG SMBiosTableLength
  33. );
  34. NTSTATUS WmipSMBiosIdentifierRegQueryRoutine(
  35. IN PWSTR ValueName,
  36. IN ULONG ValueType,
  37. IN PVOID ValueData,
  38. IN ULONG ValueLength,
  39. IN PVOID Context,
  40. IN PVOID EntryContext
  41. );
  42. BOOLEAN WmipFindSMBiosEPSHeader(
  43. PUCHAR SMBiosVirtualAddress,
  44. ULONG BiosSize,
  45. PSMBIOS_EPS_HEADER EPSHeader
  46. );
  47. NTSTATUS WmipFindSMBiosStructure(
  48. IN UCHAR Type,
  49. OUT PVOID *StructPtr,
  50. OUT PVOID *MapPtr,
  51. OUT PULONG MapSize
  52. );
  53. NTSTATUS WmipFindSysIdTable(
  54. PPHYSICAL_ADDRESS SysidTablePhysicalAddress,
  55. PUCHAR SysIdBiosRevision,
  56. PULONG NumberEntries
  57. );
  58. NTSTATUS WmipParseSysIdTable(
  59. PHYSICAL_ADDRESS PhysicalAddress,
  60. ULONG NumberEntries,
  61. PSYSID_UUID SysIdUuid,
  62. ULONG *SysIdUuidCount,
  63. PSYSID_1394 SysId1394,
  64. ULONG *SysId1394Count
  65. );
  66. NTSTATUS WmipGetSysIds(
  67. PSYSID_UUID *SysIdUuid,
  68. ULONG *SysIdUuidCount,
  69. PSYSID_1394 *SysId1394,
  70. ULONG *SysId1394Count
  71. );
  72. #ifdef ALLOC_DATA_PRAGMA
  73. #pragma data_seg("PAGEDATA")
  74. #endif
  75. //
  76. // These hold pointers to the SMBIOS data. If SMBIOS data is in the table
  77. // format then WmipSMBiosTablePhysicalAddress holds the physical address of
  78. // the table. If the SMBIOS was gathered at boot time by NTDETECT then
  79. // WmipSMBiosTableVirtualAddress holds a pointer to a paged pool buffer that
  80. // contains the SMBIOS data. In both cases WmipSMBiosTableLength holds the
  81. // actual length of the SMBIOS table. If both the physical and virtual
  82. // addresses are 0 then SMBIOS data is not available.
  83. PHYSICAL_ADDRESS WmipSMBiosTablePhysicalAddress = {0};
  84. PUCHAR WmipSMBiosTableVirtualAddress = NULL;
  85. ULONG WmipSMBiosTableLength = 0;
  86. SMBIOSVERSIONINFO WmipSMBiosVersionInfo = {0};
  87. BOOLEAN WmipSMBiosChecked = FALSE;
  88. //
  89. // Have we tried to get SYSID yet and if so what was the utilmate status
  90. BOOLEAN WmipSysIdRead;
  91. NTSTATUS WmipSysIdStatus;
  92. //
  93. // Count and arrays of UUIDs and 1394 ids
  94. PSYSID_UUID WmipSysIdUuid;
  95. ULONG WmipSysIdUuidCount;
  96. PSYSID_1394 WmipSysId1394;
  97. ULONG WmipSysId1394Count;
  98. #ifdef ALLOC_PRAGMA
  99. #pragma alloc_text(INIT,WmipGetSMBiosFromLoaderBlock)
  100. #pragma alloc_text(PAGE,WmipFindSMBiosEPSHeader)
  101. #pragma alloc_text(PAGE,WmipFindSMBiosTable)
  102. #pragma alloc_text(PAGE,WmipFindSMBiosStructure)
  103. #pragma alloc_text(PAGE,WmipFindSysIdTable)
  104. #pragma alloc_text(PAGE,WmipParseSysIdTable)
  105. #pragma alloc_text(PAGE,WmipGetSysIds)
  106. #pragma alloc_text(PAGE,WmipGetSMBiosTableData)
  107. #pragma alloc_text(PAGE,WmipGetSMBiosEventlog)
  108. #pragma alloc_text(PAGE,WmipDockUndockEventCallback)
  109. #pragma alloc_text(PAGE,WmipSMBiosDataRegQueryRoutine)
  110. #pragma alloc_text(PAGE,WmipSMBiosIdentifierRegQueryRoutine)
  111. #pragma alloc_text(PAGE,WmipIsSMBiosKey)
  112. #endif
  113. BOOLEAN WmipFindSMBiosEPSHeader(
  114. PUCHAR SMBiosVirtualAddress,
  115. ULONG BiosSize,
  116. PSMBIOS_EPS_HEADER EPSHeader
  117. )
  118. /*++
  119. Routine Description:
  120. Search for the SMBIOS 2.1 EPS structure and copy it.
  121. Arguments:
  122. SMBiosVirtualAddress is the beginning virtual address to start searching
  123. for the SMBIOS 2.1 EPS anchor string.
  124. BiosSize is the number of bytes to search for the anchor string
  125. EPSHeader is the memory into which the EPS header is copied
  126. Return Value:
  127. Pointer to SMBIOS 2.1 EPS or NULL if EPS not found
  128. --*/
  129. {
  130. PUCHAR SearchEnd;
  131. UCHAR CheckSum;
  132. PSMBIOS_EPS_HEADER SMBiosEPSHeader;
  133. PDMIBIOS_EPS_HEADER DMIBiosEPSHeader;
  134. ULONG i;
  135. ULONG CheckLength;
  136. PAGED_CODE();
  137. RtlZeroMemory(EPSHeader, sizeof(SMBIOS_EPS_HEADER));
  138. //
  139. // Scan the bios for the two anchor strings that that signal the SMBIOS
  140. // table.
  141. SearchEnd = SMBiosVirtualAddress + SMBIOS_EPS_SEARCH_SIZE -
  142. 2 * SMBIOS_EPS_SEARCH_INCREMENT;
  143. while (SMBiosVirtualAddress < SearchEnd)
  144. {
  145. SMBiosEPSHeader = (PSMBIOS_EPS_HEADER)SMBiosVirtualAddress;
  146. DMIBiosEPSHeader = (PDMIBIOS_EPS_HEADER)SMBiosVirtualAddress;
  147. //
  148. // First check for _DMI_ anchor string
  149. if ((*((PULONG)DMIBiosEPSHeader->Signature2) == DMI_EPS_SIGNATURE) &&
  150. (DMIBiosEPSHeader->Signature2[4] == '_'))
  151. {
  152. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: Found possible DMIBIOS EPS Header at %x\n", SMBiosEPSHeader));
  153. CheckLength = sizeof(DMIBIOS_EPS_HEADER);
  154. }
  155. //
  156. // Then check for full _SM_ anchor string
  157. else if ((*((PULONG)SMBiosEPSHeader->Signature) == SMBIOS_EPS_SIGNATURE) &&
  158. (SMBiosEPSHeader->Length >= sizeof(SMBIOS_EPS_HEADER)) &&
  159. (*((PULONG)SMBiosEPSHeader->Signature2) == DMI_EPS_SIGNATURE) &&
  160. (SMBiosEPSHeader->Signature2[4] == '_' ))
  161. {
  162. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: Found possible SMBIOS EPS Header at %p\n", SMBiosEPSHeader));
  163. CheckLength = SMBiosEPSHeader->Length;
  164. } else {
  165. //
  166. // Did not find anchor string, go search next paragraph
  167. SMBiosVirtualAddress += SMBIOS_EPS_SEARCH_INCREMENT;
  168. continue;
  169. }
  170. //
  171. // Verify anchor string with checksum
  172. CheckSum = 0;
  173. for (i = 0; i < CheckLength ; i++)
  174. {
  175. CheckSum += SMBiosVirtualAddress[i];
  176. }
  177. if (CheckSum == 0)
  178. {
  179. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: Found SMBIOS EPS Header at %p\n", SMBiosEPSHeader));
  180. if (CheckLength == sizeof(DMIBIOS_EPS_HEADER))
  181. {
  182. //
  183. // We only had got a DMI header so copy that
  184. //
  185. RtlCopyMemory(&EPSHeader->Signature2[0],
  186. DMIBiosEPSHeader,
  187. sizeof(DMIBIOS_EPS_HEADER));
  188. } else {
  189. //
  190. // We got the full SMBIOS header so copy that
  191. //
  192. RtlCopyMemory(EPSHeader,
  193. SMBiosEPSHeader,
  194. sizeof(SMBIOS_EPS_HEADER));
  195. }
  196. return(TRUE);
  197. }
  198. SMBiosVirtualAddress += SMBIOS_EPS_SEARCH_INCREMENT;
  199. }
  200. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: SMBIOS EPS Header not found\n"));
  201. return(FALSE);
  202. }
  203. #ifndef _IA64_
  204. //
  205. // On X86 we look at the hardware device description keys to find the
  206. // one that contains the SMBIOS data. The key is created by NTDETECT in
  207. // the case that the machine only supports the 2.0 calling mechanism
  208. //
  209. //
  210. // For x86 and ia64 the key is Someplace like
  211. // HKLM\Hardware\System\MultiFunctionAdapter\<some number>
  212. //
  213. NTSTATUS WmipSMBiosIdentifierRegQueryRoutine(
  214. IN PWSTR ValueName,
  215. IN ULONG ValueType,
  216. IN PVOID ValueData,
  217. IN ULONG ValueLength,
  218. IN PVOID Context,
  219. IN PVOID EntryContext
  220. )
  221. /*++
  222. Routine Description:
  223. Registry query values callback routine for reading SMBIOS data from
  224. registry.
  225. Arguments:
  226. ValueName - the name of the value
  227. ValueType - the type of the value
  228. ValueData - the data in the value (unicode string data)
  229. ValueLength - the number of bytes in the value data
  230. Context - Not used
  231. EntryContext - Pointer to PUCHAR to store a pointer to
  232. store the SMBIOS data read from the registry value. If this is NULL
  233. then the caller is not interested in the SMBIOS data
  234. Return Value:
  235. NT Status code -
  236. STATUS_SUCCESS - Identifier is valid for SMBIOS key
  237. STATUS_UNSUCCESSFUL - Identifier is not valid for SMBIOS key
  238. --*/
  239. {
  240. NTSTATUS Status;
  241. PAGED_CODE();
  242. Status = ((ValueType == REG_SZ) &&
  243. (ValueData != NULL) &&
  244. (wcscmp(ValueData, SMBIOSIDENTIFIERVALUEDATA) == 0)) ?
  245. STATUS_SUCCESS :
  246. STATUS_UNSUCCESSFUL;
  247. return(Status);
  248. }
  249. NTSTATUS WmipSMBiosDataRegQueryRoutine(
  250. IN PWSTR ValueName,
  251. IN ULONG ValueType,
  252. IN PVOID ValueData,
  253. IN ULONG ValueLength,
  254. IN PVOID Context,
  255. IN PVOID EntryContext
  256. )
  257. /*++
  258. Routine Description:
  259. Registry query values callback routine for reading SMBIOS data from
  260. registry.
  261. Arguments:
  262. ValueName - the name of the value
  263. ValueType - the type of the value
  264. ValueData - the data in the value (unicode string data)
  265. ValueLength - the number of bytes in the value data
  266. Context - Not used
  267. EntryContext - Pointer to PUCHAR to store a pointer to
  268. store the SMBIOS data read from the registry value. If this is NULL
  269. then the caller is not interested in the SMBIOS data
  270. Return Value:
  271. NT Status code -
  272. STATUS_SUCCESS - SMBIOS data is present in the value
  273. STATUS_INSUFFICIENT_RESOURCES - Not enough memory to keep SMBIOS data
  274. STATUS_UNSUCCESSFUL - SMBios data is not present in the value
  275. --*/
  276. {
  277. NTSTATUS Status;
  278. PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
  279. PUCHAR Buffer;
  280. PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
  281. ULONG BufferSize;
  282. PREGQUERYBUFFERXFER RegQueryBufferXfer;
  283. PAGED_CODE();
  284. WmipAssert(EntryContext != NULL);
  285. if ((ValueType == REG_FULL_RESOURCE_DESCRIPTOR) &&
  286. (ValueData != NULL))
  287. {
  288. //
  289. // On x86 get the actual SMBIOS data out of the registry and
  290. // place it into a buffer
  291. //
  292. RegQueryBufferXfer = (PREGQUERYBUFFERXFER)EntryContext;
  293. PartialResourceList = &(((PCM_FULL_RESOURCE_DESCRIPTOR)ValueData)->PartialResourceList);
  294. if (PartialResourceList->Count > 1)
  295. {
  296. //
  297. // Second partial resource descriptor contains SMBIOS data. There
  298. // should ALWAYS be a second partial resource descriptor and it
  299. // may have 0 bytes in the case that SMBIOS data was not collected
  300. // by NTDETECT.
  301. PartialDescriptor = &PartialResourceList->PartialDescriptors[0];
  302. Buffer = (PUCHAR)PartialDescriptor +
  303. sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) +
  304. PartialDescriptor->u.DeviceSpecificData.DataSize;
  305. PartialDescriptor = (PCM_PARTIAL_RESOURCE_DESCRIPTOR)Buffer;
  306. BufferSize = PartialDescriptor->u.DeviceSpecificData.DataSize;
  307. RegQueryBufferXfer->BufferSize = BufferSize;
  308. Status = STATUS_SUCCESS;
  309. if (BufferSize > 0)
  310. {
  311. RegQueryBufferXfer->Buffer = (PUCHAR)ExAllocatePoolWithTag(
  312. PagedPool,
  313. BufferSize,
  314. WMIPOOLTAG);
  315. if (RegQueryBufferXfer->Buffer != NULL)
  316. {
  317. Buffer += sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
  318. RtlCopyMemory(RegQueryBufferXfer->Buffer,
  319. Buffer,
  320. BufferSize);
  321. } else {
  322. Status = STATUS_INSUFFICIENT_RESOURCES;
  323. }
  324. }
  325. } else {
  326. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: Old NTDETECT.COM - No SMBIOS partial resource descriptor\n"));
  327. Status = STATUS_SUCCESS;
  328. RegQueryBufferXfer->BufferSize = 0;
  329. }
  330. } else {
  331. Status = STATUS_UNSUCCESSFUL;
  332. }
  333. return(Status);
  334. }
  335. BOOLEAN WmipIsSMBiosKey(
  336. HANDLE ParentKeyHandle,
  337. PWCHAR KeyName,
  338. PUCHAR *SMBiosTableVirtualAddress,
  339. PULONG SMBiosTableLength
  340. )
  341. {
  342. NTSTATUS Status;
  343. OBJECT_ATTRIBUTES ObjectAttributes;
  344. UNICODE_STRING BaseKeyName;
  345. HANDLE KeyHandle;
  346. RTL_QUERY_REGISTRY_TABLE QueryTable[3];
  347. REGQUERYBUFFERXFER RegQueryBufferXfer = {0, NULL};
  348. PAGED_CODE();
  349. RtlInitUnicodeString(&BaseKeyName,
  350. KeyName);
  351. InitializeObjectAttributes(&ObjectAttributes,
  352. &BaseKeyName,
  353. OBJ_CASE_INSENSITIVE,
  354. ParentKeyHandle,
  355. NULL);
  356. Status = ZwOpenKey(&KeyHandle,
  357. KEY_READ,
  358. &ObjectAttributes);
  359. if (NT_SUCCESS(Status))
  360. {
  361. RtlZeroMemory(QueryTable, sizeof(QueryTable));
  362. QueryTable[0].Name = SMBIOSIDENTIFIERVALUENAME;
  363. QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
  364. QueryTable[0].DefaultType = REG_SZ;
  365. QueryTable[0].QueryRoutine = WmipSMBiosIdentifierRegQueryRoutine;
  366. QueryTable[1].Name = SMBIOSDATAVALUENAME;
  367. QueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED;
  368. QueryTable[1].EntryContext = &RegQueryBufferXfer;
  369. QueryTable[1].DefaultType = REG_FULL_RESOURCE_DESCRIPTOR;
  370. QueryTable[1].QueryRoutine = WmipSMBiosDataRegQueryRoutine;
  371. Status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE | RTL_REGISTRY_ABSOLUTE,
  372. (PWCHAR)KeyHandle,
  373. QueryTable,
  374. NULL,
  375. NULL);
  376. if (NT_SUCCESS(Status))
  377. {
  378. *SMBiosTableVirtualAddress = RegQueryBufferXfer.Buffer;
  379. *SMBiosTableLength = RegQueryBufferXfer.BufferSize;
  380. }
  381. ZwClose(KeyHandle);
  382. } else {
  383. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: H/D/S/MultifunctionAdapter subkey open error %x\n",
  384. Status));
  385. }
  386. return(NT_SUCCESS(Status));
  387. }
  388. #endif
  389. BOOLEAN WmipFindSMBiosTable(
  390. PPHYSICAL_ADDRESS SMBiosTablePhysicalAddress,
  391. PUCHAR *SMBiosTableVirtualAddress,
  392. PULONG SMBiosTableLength,
  393. PSMBIOSVERSIONINFO SMBiosVersionInfo
  394. )
  395. /*++
  396. Routine Description:
  397. Determines if the SMBIOS data is available
  398. Arguments:
  399. SMBiosTablePhysicalAddress points to a variable to return the physical
  400. address of the SMBIOS 2.1 table. If table is not available then
  401. it returns with 0.
  402. SMBiosTableVirtualAddress points to a variable to return the virtual
  403. address of the SMBIOS 2.0 table as collected by NTDETECT. If the
  404. SMBIOS 2.0 data was not collected by NTDETECT it returns with 0.
  405. SMBiosTableLength points to a variable to return the length of the
  406. SMBIOS table data.
  407. SMBiosVersionInfo returns with the version information for SMBIOS
  408. Return Value:
  409. TRUE if SMBIOS data is available, else FALSE
  410. --*/
  411. {
  412. PHYSICAL_ADDRESS BiosPhysicalAddress;
  413. PUCHAR BiosVirtualAddress;
  414. PDMIBIOS_EPS_HEADER DMIBiosEPSHeader;
  415. NTSTATUS Status;
  416. UNICODE_STRING BaseKeyName;
  417. HANDLE KeyHandle;
  418. ULONG KeyInformationLength;
  419. ULONG KeyIndex;
  420. UCHAR KeyInformationBuffer[sizeof(KEY_BASIC_INFORMATION) +
  421. (sizeof(WCHAR) * MAXSMBIOSKEYNAMESIZE)];
  422. PKEY_BASIC_INFORMATION KeyInformation;
  423. OBJECT_ATTRIBUTES ObjectAttributes;
  424. SMBIOS_EPS_HEADER SMBiosEPSHeader;
  425. BOOLEAN HaveEPSHeader = FALSE;
  426. BOOLEAN SearchForHeader = TRUE;
  427. PAGED_CODE();
  428. SMBiosTablePhysicalAddress->QuadPart = 0;
  429. *SMBiosTableVirtualAddress = NULL;
  430. *SMBiosTableLength = 0;
  431. #ifndef _IA64_
  432. //
  433. // First check registry to see if we captured SMBIOS 2.0 data in
  434. // NTDETECT. Search the keys under
  435. // MultiFunctionAdapter for the one
  436. // with the "PnP Bios" (x86)
  437. //
  438. RtlInitUnicodeString(&BaseKeyName,
  439. SMBIOSPARENTKEYNAME);
  440. InitializeObjectAttributes(&ObjectAttributes,
  441. &BaseKeyName,
  442. OBJ_CASE_INSENSITIVE,
  443. NULL,
  444. NULL);
  445. Status = ZwOpenKey(&KeyHandle,
  446. KEY_READ,
  447. &ObjectAttributes);
  448. if (NT_SUCCESS(Status))
  449. {
  450. KeyIndex = 0;
  451. KeyInformation = (PKEY_BASIC_INFORMATION)KeyInformationBuffer;
  452. while (NT_SUCCESS(Status))
  453. {
  454. Status = ZwEnumerateKey(KeyHandle,
  455. KeyIndex++,
  456. KeyBasicInformation,
  457. KeyInformation,
  458. sizeof(KeyInformationBuffer) - sizeof(WCHAR),
  459. &KeyInformationLength);
  460. if (NT_SUCCESS(Status))
  461. {
  462. KeyInformation->Name[KeyInformation->NameLength / sizeof(WCHAR)] = UNICODE_NULL;
  463. if (WmipIsSMBiosKey(KeyHandle,
  464. KeyInformation->Name,
  465. SMBiosTableVirtualAddress,
  466. SMBiosTableLength))
  467. {
  468. if (*SMBiosTableLength != 0)
  469. {
  470. SMBiosVersionInfo->Used20CallingMethod = TRUE;
  471. SearchForHeader = FALSE;
  472. }
  473. break;
  474. }
  475. } else {
  476. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: Status %x enum H\\D\\S\\MultiFunctionAdapter key, index %d\n",
  477. Status, KeyIndex-1));
  478. }
  479. }
  480. ZwClose(KeyHandle);
  481. } else {
  482. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: Status %x opening H\\D\\S\\MultiFunctionAdapter key\n",
  483. Status));
  484. }
  485. #endif
  486. if (SearchForHeader)
  487. {
  488. //
  489. // If not in registry then check for EPS in the BIOS
  490. BiosPhysicalAddress.QuadPart = SMBIOS_EPS_SEARCH_START;
  491. BiosVirtualAddress = MmMapIoSpace(BiosPhysicalAddress,
  492. SMBIOS_EPS_SEARCH_SIZE,
  493. MmCached);
  494. if (BiosVirtualAddress != NULL)
  495. {
  496. HaveEPSHeader = WmipFindSMBiosEPSHeader(BiosVirtualAddress,
  497. SMBIOS_EPS_SEARCH_SIZE,
  498. &SMBiosEPSHeader);
  499. MmUnmapIoSpace(BiosVirtualAddress, SMBIOS_EPS_SEARCH_SIZE);
  500. }
  501. } else {
  502. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: SMBIOS data recovered from loader\n"));
  503. }
  504. if (HaveEPSHeader)
  505. {
  506. //
  507. // We found the EPS so just extract the physical
  508. // address of the table
  509. //
  510. DMIBiosEPSHeader = (PDMIBIOS_EPS_HEADER)&SMBiosEPSHeader.Signature2[0];
  511. SMBiosVersionInfo->Used20CallingMethod = FALSE;
  512. SMBiosTablePhysicalAddress->HighPart = 0;
  513. SMBiosTablePhysicalAddress->LowPart = DMIBiosEPSHeader->StructureTableAddress;
  514. *SMBiosTableLength = DMIBiosEPSHeader->StructureTableLength;
  515. SMBiosVersionInfo->SMBiosMajorVersion = SMBiosEPSHeader.MajorVersion;
  516. SMBiosVersionInfo->SMBiosMinorVersion = SMBiosEPSHeader.MinorVersion;
  517. SMBiosVersionInfo->DMIBiosRevision = DMIBiosEPSHeader->Revision;
  518. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: SMBIOS 2.1 data at (%x%x) size %x \n",
  519. SMBiosTablePhysicalAddress->HighPart,
  520. SMBiosTablePhysicalAddress->LowPart,
  521. *SMBiosTableLength));
  522. }
  523. return(*SMBiosTableLength > 0);
  524. }
  525. NTSTATUS WmipGetSMBiosTableData(
  526. OUT PUCHAR Buffer,
  527. IN OUT PULONG BufferSize,
  528. OUT PSMBIOSVERSIONINFO SMBiosVersionInfo
  529. )
  530. /*++
  531. Routine Description:
  532. Registry query values callback routine for reading SMBIOS data from
  533. registry.
  534. Arguments:
  535. Buffer is a pointer to a buffer in which to write the SMBIOS data
  536. *BufferSize has the maximum number of bytes available to write into
  537. Buffer. On return it has the actual size of the SMBIOS data.
  538. Return Value:
  539. NT Status code -
  540. STATUS_SUCCESS - Buffer filled with SMBIOS data
  541. STATUS_BUFFER_TOO_SMALL - Buffer not filled with SMBIOS data,
  542. *BufferSize returns with buffer size neeeded
  543. --*/
  544. {
  545. NTSTATUS status;
  546. PUCHAR SMBiosDataVirtualAddress;
  547. PAGED_CODE();
  548. WmipEnterSMCritSection();
  549. if (! WmipSMBiosChecked)
  550. {
  551. //
  552. // See if there is any SMBIOS information and if so register
  553. WmipFindSMBiosTable(&WmipSMBiosTablePhysicalAddress,
  554. &WmipSMBiosTableVirtualAddress,
  555. &WmipSMBiosTableLength,
  556. &WmipSMBiosVersionInfo);
  557. WmipSMBiosChecked = TRUE;
  558. }
  559. WmipLeaveSMCritSection();
  560. if (SMBiosVersionInfo != NULL)
  561. {
  562. *SMBiosVersionInfo = WmipSMBiosVersionInfo;
  563. }
  564. if (*BufferSize >= WmipSMBiosTableLength)
  565. {
  566. if (WmipSMBiosTablePhysicalAddress.QuadPart != 0)
  567. {
  568. //
  569. // 2.1 table format - map in table and copy
  570. SMBiosDataVirtualAddress = MmMapIoSpace(WmipSMBiosTablePhysicalAddress,
  571. WmipSMBiosTableLength,
  572. MmCached);
  573. if (SMBiosDataVirtualAddress != NULL)
  574. {
  575. RtlCopyMemory(Buffer,
  576. SMBiosDataVirtualAddress,
  577. WmipSMBiosTableLength);
  578. MmUnmapIoSpace(SMBiosDataVirtualAddress,
  579. WmipSMBiosTableLength);
  580. status = STATUS_SUCCESS;
  581. } else {
  582. status = STATUS_INSUFFICIENT_RESOURCES;
  583. }
  584. } else if (WmipSMBiosTableVirtualAddress != NULL) {
  585. RtlCopyMemory(Buffer,
  586. WmipSMBiosTableVirtualAddress,
  587. WmipSMBiosTableLength);
  588. status = STATUS_SUCCESS;
  589. } else {
  590. status = STATUS_INVALID_DEVICE_REQUEST;
  591. }
  592. } else {
  593. status = STATUS_BUFFER_TOO_SMALL;
  594. }
  595. *BufferSize = WmipSMBiosTableLength;
  596. return(status);
  597. }
  598. #if defined(_IA64_) // EFI actually
  599. void WmipGetSMBiosFromLoaderBlock(
  600. PVOID LoaderBlockPtr
  601. )
  602. {
  603. PLOADER_PARAMETER_BLOCK LoaderBlock = (PLOADER_PARAMETER_BLOCK)LoaderBlockPtr;
  604. PLOADER_PARAMETER_EXTENSION LoaderExtension = LoaderBlock->Extension;
  605. PSMBIOS_EPS_HEADER SMBiosEPSHeader;
  606. PDMIBIOS_EPS_HEADER DMIBiosEPSHeader;
  607. PAGED_CODE();
  608. if (LoaderExtension->Size >= sizeof(LOADER_PARAMETER_EXTENSION))
  609. {
  610. SMBiosEPSHeader = LoaderExtension->SMBiosEPSHeader;
  611. if (SMBiosEPSHeader != NULL)
  612. {
  613. DMIBiosEPSHeader = (PDMIBIOS_EPS_HEADER)&SMBiosEPSHeader->Signature2[0];
  614. WmipSMBiosVersionInfo.Used20CallingMethod = FALSE;
  615. WmipSMBiosTablePhysicalAddress.HighPart = 0;
  616. WmipSMBiosTablePhysicalAddress.LowPart = DMIBiosEPSHeader->StructureTableAddress;
  617. WmipSMBiosTableLength = DMIBiosEPSHeader->StructureTableLength;
  618. WmipSMBiosVersionInfo.SMBiosMajorVersion = SMBiosEPSHeader->MajorVersion;
  619. WmipSMBiosVersionInfo.SMBiosMinorVersion = SMBiosEPSHeader->MinorVersion;
  620. WmipSMBiosVersionInfo.DMIBiosRevision = DMIBiosEPSHeader->Revision;
  621. WmipSMBiosChecked = TRUE;
  622. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,
  623. "WMI: SMBIOS 2.1 data from EFI at (%x%x) size %x \n",
  624. WmipSMBiosTablePhysicalAddress.HighPart,
  625. WmipSMBiosTablePhysicalAddress.LowPart,
  626. WmipSMBiosTableLength));
  627. } else {
  628. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,
  629. "WMI: No SMBIOS data in loader block\n"));
  630. }
  631. } else {
  632. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,
  633. "WMI: Loader extension does not contain SMBIOS header\n"));
  634. }
  635. }
  636. #endif
  637. #define WmipUnmapSMBiosStructure(Address, Size) \
  638. if ((Address) != NULL) MmUnmapIoSpace((Address), (Size));
  639. NTSTATUS WmipFindSMBiosStructure(
  640. IN UCHAR Type,
  641. OUT PVOID *StructPtr,
  642. OUT PVOID *MapPtr,
  643. OUT PULONG MapSize
  644. )
  645. /*++
  646. Routine Description:
  647. Find a specific SMBIOS structure in the SMBIOS information.
  648. WmipUnmapSNVuisStructure should be called if this function returns
  649. successfully.
  650. Arguments:
  651. Type is structure type to find
  652. *StructPtr returns with pointer to beginning of structure
  653. *MapPtr returns with pointer to address SMBIOS data was mapped.
  654. *MapSize returns with size mapped
  655. Return Value:
  656. STATUS
  657. --*/
  658. {
  659. NTSTATUS Status;
  660. BOOLEAN Found;
  661. PUCHAR Ptr;
  662. PUCHAR PtrEnd;
  663. PSMBIOS_STRUCT_HEADER StructHeader;
  664. PAGED_CODE();
  665. //
  666. // Make sure SMBIOS table has been obtained. Note we already hold
  667. // the critical section
  668. if (! WmipSMBiosChecked)
  669. {
  670. //
  671. // See if there is any SMBIOS information and if so register
  672. Found = WmipFindSMBiosTable(&WmipSMBiosTablePhysicalAddress,
  673. &WmipSMBiosTableVirtualAddress,
  674. &WmipSMBiosTableLength,
  675. &WmipSMBiosVersionInfo);
  676. WmipSMBiosChecked = TRUE;
  677. } else {
  678. Found = (WmipSMBiosTableLength > 0);
  679. }
  680. if (Found)
  681. {
  682. Status = STATUS_SUCCESS;
  683. if (WmipSMBiosTablePhysicalAddress.QuadPart != 0)
  684. {
  685. //
  686. // SMBIOS is available in physical memory
  687. *MapPtr = MmMapIoSpace(WmipSMBiosTablePhysicalAddress,
  688. WmipSMBiosTableLength,
  689. MmCached);
  690. if (*MapPtr != NULL)
  691. {
  692. *MapSize = WmipSMBiosTableLength;
  693. Ptr = *MapPtr;
  694. } else {
  695. //
  696. // Lets hope this is a temporary problem
  697. Status = STATUS_INSUFFICIENT_RESOURCES;
  698. }
  699. } else if (WmipSMBiosTableVirtualAddress != NULL) {
  700. *MapPtr = NULL;
  701. Ptr = WmipSMBiosTableVirtualAddress;
  702. } else {
  703. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: SMBIOS table was found, but is not in physical or virtual memory\n"));
  704. WmipAssert(FALSE);
  705. Status = STATUS_UNSUCCESSFUL;
  706. }
  707. if (NT_SUCCESS(Status))
  708. {
  709. //
  710. // Now scan the SMBIOS table to find our structure
  711. *StructPtr = NULL;
  712. PtrEnd = (PVOID)((PUCHAR)Ptr + WmipSMBiosTableLength);
  713. Status = STATUS_UNSUCCESSFUL;
  714. try
  715. {
  716. while (Ptr < PtrEnd)
  717. {
  718. StructHeader = (PSMBIOS_STRUCT_HEADER)Ptr;
  719. if (StructHeader->Type == Type)
  720. {
  721. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: SMBIOS struct for type %d found at %p\n",
  722. Type, Ptr));
  723. *StructPtr = Ptr;
  724. Status = STATUS_SUCCESS;
  725. break;
  726. }
  727. Ptr+= StructHeader->Length;
  728. while ( (*((USHORT UNALIGNED *)Ptr) != 0) &&
  729. (Ptr < PtrEnd) )
  730. {
  731. Ptr++;
  732. }
  733. Ptr += 2;
  734. }
  735. } except(EXCEPTION_EXECUTE_HANDLER) {
  736. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: Invalid SMBIOS data table %p at %p\n",
  737. *MapPtr, StructHeader));
  738. WmipAssert(FALSE);
  739. }
  740. if (! NT_SUCCESS(Status) )
  741. {
  742. WmipUnmapSMBiosStructure(*MapPtr, *MapSize);
  743. }
  744. }
  745. } else {
  746. Status = STATUS_UNSUCCESSFUL;
  747. }
  748. return(Status);
  749. }
  750. NTSTATUS WmipFindSysIdTable(
  751. PPHYSICAL_ADDRESS SysidTablePhysicalAddress,
  752. PUCHAR SysIdBiosRevision,
  753. PULONG NumberEntries
  754. )
  755. /*++
  756. Routine Description:
  757. Scan the system bios to search for the SYSID table
  758. Arguments:
  759. *SysidTablePhysicalAddress returns with the physical address of the
  760. sysid table
  761. *SysIdBiosRevision returns with the bios revision of the sysid table
  762. *NumberEntries returns the number of SYSID entries in the table
  763. Return Value:
  764. STATUS
  765. --*/
  766. {
  767. UCHAR Checksum;
  768. PUCHAR p;
  769. PSYSID_EPS_HEADER SysIdEps, SearchEnd;
  770. PHYSICAL_ADDRESS BiosPhysicalAddress;
  771. PUCHAR BiosVirtualAddress;
  772. ULONG i;
  773. NTSTATUS Status;
  774. PAGED_CODE();
  775. BiosPhysicalAddress.QuadPart = SYSID_EPS_SEARCH_START;
  776. BiosVirtualAddress = MmMapIoSpace(BiosPhysicalAddress,
  777. SYSID_EPS_SEARCH_SIZE,
  778. MmCached);
  779. SearchEnd = (PSYSID_EPS_HEADER)(BiosVirtualAddress + SYSID_EPS_SEARCH_SIZE);
  780. SysIdEps = (PSYSID_EPS_HEADER)BiosVirtualAddress;
  781. if (BiosVirtualAddress != NULL)
  782. {
  783. try
  784. {
  785. while (SysIdEps < SearchEnd)
  786. {
  787. if (((*(PULONG)SysIdEps->Signature) == SYSID_EPS_SIGNATURE) &&
  788. (*(PUSHORT)(&SysIdEps->Signature[4]) == SYSID_EPS_SIGNATURE2) &&
  789. (SysIdEps->Signature[6] == '_') )
  790. {
  791. //
  792. // This may be the SYSID table, check the checksum
  793. Checksum = 0;
  794. p = (PUCHAR)SysIdEps;
  795. for (i = 0; i < sizeof(SYSID_EPS_HEADER); i++)
  796. {
  797. Checksum += p[i];
  798. }
  799. if (Checksum == 0)
  800. {
  801. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: SYSID EPS found at %p\n",
  802. SysIdEps));
  803. break;
  804. } else {
  805. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: Invalis SYSID EPS checksum at %p\n",
  806. SysIdEps));
  807. }
  808. }
  809. SysIdEps = (PSYSID_EPS_HEADER)( ((PUCHAR)SysIdEps) +
  810. SYSID_EPS_SEARCH_INCREMENT);
  811. }
  812. if (SysIdEps != SearchEnd)
  813. {
  814. SysidTablePhysicalAddress->HighPart = 0;
  815. SysidTablePhysicalAddress->LowPart = SysIdEps->SysIdTableAddress;
  816. *SysIdBiosRevision = SysIdEps->BiosRev;
  817. *NumberEntries = SysIdEps->SysIdCount;
  818. Status = STATUS_SUCCESS;
  819. } else {
  820. //
  821. // Not finding the SYSID EPS is a terminal error
  822. Status = STATUS_UNSUCCESSFUL;
  823. }
  824. } except(EXCEPTION_EXECUTE_HANDLER) {
  825. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: Invalid SYSID EPS Table at %p\n", SysIdEps));
  826. Status = STATUS_UNSUCCESSFUL;
  827. }
  828. MmUnmapIoSpace(BiosVirtualAddress, SYSID_EPS_SEARCH_SIZE);
  829. } else {
  830. //
  831. // Lets hope that failure to map memory is a temporary problem
  832. Status = STATUS_INSUFFICIENT_RESOURCES;
  833. }
  834. return(Status);
  835. }
  836. typedef enum
  837. {
  838. SYSID_UNKNOWN_TYPE,
  839. SYSID_UUID_TYPE,
  840. SYSID_1394_TYPE
  841. } SYSID_ENTRY_TYPE, *PSYSID_ENTRY_TYPE;
  842. NTSTATUS WmipParseSysIdTable(
  843. PHYSICAL_ADDRESS PhysicalAddress,
  844. ULONG NumberEntries,
  845. PSYSID_UUID SysIdUuid,
  846. ULONG *SysIdUuidCount,
  847. PSYSID_1394 SysId1394,
  848. ULONG *SysId1394Count
  849. )
  850. /*++
  851. Routine Description:
  852. Determine the set of UUIDs and 1394 Ids that are in the sysid table
  853. Arguments:
  854. PhysicalAddress is the physical address of the SysId table
  855. NumberEntries is the number of entries in the SysId table
  856. SysIdUuid returns filled with an array of UUIDs. If NULL then no
  857. UUIDs are returned.
  858. *SysIdUuidCount returns with the number of UUIDs in the table
  859. SysId1394 returns filled with an array of 1394 ids. If NULL then no
  860. 1394 ids are returned.
  861. *SysId1394Count returns with the number of 1394 ids in the table
  862. Return Value:
  863. STATUS
  864. --*/
  865. {
  866. NTSTATUS Status;
  867. ULONG TableSize = NumberEntries * LARGEST_SYSID_TABLE_ENTRY;
  868. ULONG i;
  869. ULONG j;
  870. PUCHAR VirtualAddress;
  871. PSYSID_TABLE_ENTRY SysId;
  872. PUCHAR p;
  873. UCHAR Checksum;
  874. ULONG Length;
  875. ULONG x1394Count, UuidCount;
  876. ULONG BytesLeft;
  877. SYSID_ENTRY_TYPE SysidType;
  878. PAGED_CODE();
  879. VirtualAddress = MmMapIoSpace(PhysicalAddress,
  880. TableSize,
  881. MmCached);
  882. if (VirtualAddress != NULL)
  883. {
  884. UuidCount = 0;
  885. x1394Count = 0;
  886. SysId = (PSYSID_TABLE_ENTRY)VirtualAddress;
  887. BytesLeft = TableSize;
  888. Status = STATUS_SUCCESS;
  889. for (i = 0; i < NumberEntries; i++)
  890. {
  891. //
  892. // Make sure we have not moved beyond the end of the mapped
  893. // memory.
  894. if (BytesLeft >= sizeof(SYSID_TABLE_ENTRY))
  895. {
  896. Length = SysId->Length;
  897. //
  898. // Determine what kind of sysid we have
  899. //
  900. if ((RtlCompareMemory(&SysId->Type,
  901. SYSID_TYPE_UUID, 6) == 6) &&
  902. (Length == sizeof(SYSID_UUID_ENTRY)))
  903. {
  904. SysidType = SYSID_UUID_TYPE;
  905. } else if ((RtlCompareMemory(&SysId->Type,
  906. SYSID_TYPE_1394, 6) == 6) &&
  907. (Length == sizeof(SYSID_1394_ENTRY))) {
  908. SysidType = SYSID_1394_TYPE;
  909. } else {
  910. //
  911. // unknown type SYSID
  912. //
  913. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: Unknown SYSID type %c%c%c%c%c%c found at %p\n",
  914. SysId->Type[0],
  915. SysId->Type[1],
  916. SysId->Type[2],
  917. SysId->Type[3],
  918. SysId->Type[4],
  919. SysId->Type[5],
  920. SysId
  921. ));
  922. Status = STATUS_UNSUCCESSFUL;
  923. break;
  924. }
  925. //
  926. // Validate checksum for this table entry
  927. if (BytesLeft >= Length)
  928. {
  929. Checksum = 0;
  930. p = (PUCHAR)SysId;
  931. for (j = 0; j < Length; j++)
  932. {
  933. Checksum = (UCHAR)(Checksum + p[j]);
  934. }
  935. if (Checksum != 0)
  936. {
  937. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: SYSID Table checksum is not valid at %p\n",
  938. SysId));
  939. Status = STATUS_UNSUCCESSFUL;
  940. break;
  941. }
  942. //
  943. // Determine what kind of SYSID we have
  944. if (SysidType == SYSID_UUID_TYPE)
  945. {
  946. if (BytesLeft >= sizeof(SYSID_UUID_ENTRY))
  947. {
  948. //
  949. // _UUID_ type SYSID
  950. UuidCount++;
  951. if (SysIdUuid != NULL)
  952. {
  953. RtlCopyMemory(SysIdUuid,
  954. SysId->Data,
  955. sizeof(SYSID_UUID));
  956. SysIdUuid++;
  957. }
  958. } else {
  959. Status = STATUS_UNSUCCESSFUL;
  960. break;
  961. }
  962. } else if (SysidType == SYSID_1394_TYPE) {
  963. if (BytesLeft >= sizeof(SYSID_1394_ENTRY))
  964. {
  965. //
  966. // _1394_ type SYSID
  967. x1394Count++;
  968. if (SysId1394 != NULL)
  969. {
  970. RtlCopyMemory(SysId1394,
  971. SysId->Data,
  972. sizeof(SYSID_1394));
  973. SysId1394++;
  974. }
  975. } else {
  976. Status = STATUS_UNSUCCESSFUL;
  977. break;
  978. }
  979. } else {
  980. WmipAssert(FALSE);
  981. Status = STATUS_UNSUCCESSFUL;
  982. break;
  983. }
  984. //
  985. // Advance to next sysid in table
  986. SysId = (PSYSID_TABLE_ENTRY)(((PUCHAR)SysId) + Length);
  987. BytesLeft -= Length;
  988. } else {
  989. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: SYSID Table at %p is larger at %p than expected",
  990. VirtualAddress, SysId));
  991. Status = STATUS_UNSUCCESSFUL;
  992. break;
  993. }
  994. } else {
  995. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: SYSID Table at %p is larger at %p than expected",
  996. VirtualAddress, SysId));
  997. Status = STATUS_UNSUCCESSFUL;
  998. break;
  999. }
  1000. }
  1001. *SysIdUuidCount = UuidCount;
  1002. *SysId1394Count = x1394Count;
  1003. MmUnmapIoSpace(VirtualAddress, TableSize);
  1004. } else {
  1005. //
  1006. // Lets hope that the failure to map is a temporary condition
  1007. Status = STATUS_INSUFFICIENT_RESOURCES;
  1008. }
  1009. return(Status);
  1010. }
  1011. NTSTATUS WmipGetSysIds(
  1012. PSYSID_UUID *SysIdUuid,
  1013. ULONG *SysIdUuidCount,
  1014. PSYSID_1394 *SysId1394,
  1015. ULONG *SysId1394Count
  1016. )
  1017. /*++
  1018. Routine Description:
  1019. This routine will obtain the 1394 and UUID sysids from the bios. First
  1020. we look for a specific memory signature that contains a list of 1394 and
  1021. UUID sysids. If we do not find that we then look at the SMBIOS information
  1022. structure SYSTEM INFORMATION (type 1) which may have it embedded within
  1023. it. If not then we give up.
  1024. Arguments:
  1025. *SysIdUuid returns pointing to an array of UUID Sysids
  1026. *SysIdUuidCount returns with the number of UUID Sysids in *SysIdUuid
  1027. *SysId1394 returns pointing to an array of 1394 Sysids
  1028. *SysId1394Count returns with the number of 1394 Sysids in *SysIdUuid
  1029. Return Value:
  1030. NT Status code
  1031. --*/
  1032. {
  1033. NTSTATUS Status;
  1034. PHYSICAL_ADDRESS PhysicalAddress;
  1035. UCHAR BiosRevision;
  1036. ULONG NumberEntries;
  1037. ULONG UuidCount, x1394Count;
  1038. PSYSID_UUID Uuid;
  1039. PSYSID_1394 x1394;
  1040. ULONG TotalSize, x1394Size, UuidSize;
  1041. PAGED_CODE();
  1042. WmipEnterSMCritSection();
  1043. //
  1044. // First See if we have already obtained the SYSIDS
  1045. if (! WmipSysIdRead)
  1046. {
  1047. //
  1048. // First see if the sysids are maintained in a separate SYSID table
  1049. Status = WmipFindSysIdTable(&PhysicalAddress,
  1050. &BiosRevision,
  1051. &NumberEntries);
  1052. if (NT_SUCCESS(Status))
  1053. {
  1054. //
  1055. // Get the count of entries in each table
  1056. Status = WmipParseSysIdTable(PhysicalAddress,
  1057. NumberEntries,
  1058. NULL,
  1059. &UuidCount,
  1060. NULL,
  1061. &x1394Count);
  1062. if (NT_SUCCESS(Status))
  1063. {
  1064. //
  1065. // Get the entire SYSID table
  1066. UuidSize = UuidCount * sizeof(SYSID_UUID);
  1067. x1394Size = x1394Count * sizeof(SYSID_1394);
  1068. TotalSize = UuidSize+x1394Size;
  1069. if (TotalSize > 0)
  1070. {
  1071. Uuid = ExAllocatePoolWithTag(PagedPool,
  1072. TotalSize,
  1073. WMISYSIDPOOLTAG);
  1074. if (Uuid == NULL)
  1075. {
  1076. WmipLeaveSMCritSection();
  1077. return(STATUS_INSUFFICIENT_RESOURCES);
  1078. }
  1079. x1394 = (PSYSID_1394)( ((PUCHAR)Uuid) + UuidSize );
  1080. //
  1081. // Now get the SYSIDs
  1082. Status = WmipParseSysIdTable(PhysicalAddress,
  1083. NumberEntries,
  1084. Uuid,
  1085. &UuidCount,
  1086. x1394,
  1087. &x1394Count);
  1088. if (NT_SUCCESS(Status))
  1089. {
  1090. WmipSysIdUuid = Uuid;
  1091. WmipSysIdUuidCount = UuidCount;
  1092. WmipSysId1394 = x1394;
  1093. WmipSysId1394Count = x1394Count;
  1094. } else {
  1095. ExFreePool(Uuid);
  1096. }
  1097. }
  1098. }
  1099. } else {
  1100. //
  1101. // Get SYSID information from SMBIOS
  1102. PVOID MapAddress;
  1103. PSMBIOS_SYSTEM_INFORMATION_STRUCT Info;
  1104. ULONG MapSize;
  1105. Status = WmipFindSMBiosStructure(SMBIOS_SYSTEM_INFORMATION,
  1106. (PVOID *)&Info,
  1107. &MapAddress,
  1108. &MapSize);
  1109. if (NT_SUCCESS(Status))
  1110. {
  1111. Uuid = NULL;
  1112. WmipSysId1394 = NULL;
  1113. WmipSysId1394Count = 0;
  1114. try
  1115. {
  1116. if (Info->Length > SMBIOS_SYSTEM_INFORMATION_LENGTH_20)
  1117. {
  1118. Uuid = ExAllocatePoolWithTag(PagedPool,
  1119. sizeof(SYSID_UUID),
  1120. WMISYSIDPOOLTAG);
  1121. if (Uuid != NULL)
  1122. {
  1123. RtlCopyMemory(Uuid,
  1124. Info->Uuid,
  1125. sizeof(SYSID_UUID));
  1126. WmipSysIdUuidCount = 1;
  1127. WmipSysIdUuid = Uuid;
  1128. Status = STATUS_SUCCESS;
  1129. } else {
  1130. ExFreePool(Uuid);
  1131. Status = STATUS_UNSUCCESSFUL;
  1132. }
  1133. } else {
  1134. WmipSysIdUuid = NULL;
  1135. WmipSysIdUuidCount = 0;
  1136. }
  1137. } except(EXCEPTION_EXECUTE_HANDLER) {
  1138. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: Invalid SMBIOS SYSTEM INFO structure %p\n",
  1139. Info));
  1140. WmipAssert(FALSE);
  1141. Status = STATUS_UNSUCCESSFUL;
  1142. }
  1143. WmipUnmapSMBiosStructure(MapAddress, MapSize);
  1144. }
  1145. }
  1146. //
  1147. // Mark that we were not able to obtain SysId Information
  1148. WmipSysIdRead = (Status != STATUS_INSUFFICIENT_RESOURCES);
  1149. WmipSysIdStatus = Status;
  1150. }
  1151. WmipLeaveSMCritSection();
  1152. if (NT_SUCCESS(WmipSysIdStatus))
  1153. {
  1154. *SysIdUuid = WmipSysIdUuid;
  1155. *SysIdUuidCount = WmipSysIdUuidCount;
  1156. *SysId1394 = WmipSysId1394;
  1157. *SysId1394Count = WmipSysId1394Count;
  1158. }
  1159. return(WmipSysIdStatus);
  1160. }
  1161. NTSTATUS WmipGetSMBiosEventlog(
  1162. PUCHAR Buffer,
  1163. PULONG BufferSize
  1164. )
  1165. /*++
  1166. Routine Description:
  1167. Return the contents of the SMBios eventlog
  1168. Arguments:
  1169. Buffer is a pointer to a buffer that receives the eventlog
  1170. *BufferSize on entry has the size of the buffer that can receive
  1171. the eventlog data, on return it has the number of bytes used
  1172. by the smbios eventlog data or the number of bytes needed for
  1173. the smbios eventlog data.
  1174. Return Value:
  1175. NT Status code -
  1176. STATUS_SUCCESS - Buffer filled with SMBIOS eventlog data
  1177. STATUS_BUFFER_TOO_SMALL - Buffer not filled with SMBIOS eventlog data,
  1178. *BufferSize returns with buffer size neeeded
  1179. --*/
  1180. {
  1181. PVOID MapAddress;
  1182. PSMBIOS_SYSTEM_EVENTLOG_STRUCT SystemEventlog;
  1183. ULONG MapSize;
  1184. USHORT LogAreaLength;
  1185. UCHAR AccessMethod;
  1186. ACCESS_METHOD_ADDRESS AccessMethodAddress;
  1187. PSMBIOS_EVENTLOG_INFO EventlogInfo;
  1188. UCHAR LogHeaderDescExists;
  1189. PUCHAR EventlogArea;
  1190. NTSTATUS Status;
  1191. USHORT LogTypeDescLength;
  1192. ULONG SizeNeeded;
  1193. PAGED_CODE();
  1194. Status = WmipFindSMBiosStructure(SMBIOS_SYSTEM_EVENTLOG,
  1195. (PVOID *)&SystemEventlog,
  1196. &MapAddress,
  1197. &MapSize);
  1198. if (NT_SUCCESS(Status))
  1199. {
  1200. //
  1201. // Copy data out of SMBIOS eventlog header so we can unmap quickly
  1202. //
  1203. LogAreaLength = SystemEventlog->LogAreaLength;
  1204. AccessMethod = SystemEventlog->AccessMethod;
  1205. AccessMethodAddress = SystemEventlog->AccessMethodAddress;
  1206. if (SystemEventlog->Length >= SMBIOS_SYSTEM_EVENTLOG_LENGTH)
  1207. {
  1208. LogTypeDescLength = SystemEventlog->NumLogTypeDescriptors *
  1209. SystemEventlog->LenLogTypeDescriptors;
  1210. LogHeaderDescExists = 1;
  1211. if (SystemEventlog->Length != (LogTypeDescLength +
  1212. FIELD_OFFSET(SMBIOS_SYSTEM_EVENTLOG_STRUCT,
  1213. LogTypeDescriptor)))
  1214. {
  1215. //
  1216. // The SMBIOS spec says that the Length of the structure
  1217. // is the length of the base part of the structures plus
  1218. // the length of the type descriptors. Since this is not
  1219. // the case we may have run into a buggy bios
  1220. //
  1221. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: SMBIOS System Eventlog struture %p size is %x, but expecting %x\n",
  1222. SystemEventlog,
  1223. SystemEventlog->Length,
  1224. (LogTypeDescLength +
  1225. FIELD_OFFSET(SMBIOS_SYSTEM_EVENTLOG_STRUCT,
  1226. LogTypeDescriptor)) ));
  1227. WmipAssert(FALSE);
  1228. WmipUnmapSMBiosStructure(MapAddress, MapSize);
  1229. Status = STATUS_UNSUCCESSFUL;
  1230. return(Status);
  1231. }
  1232. } else {
  1233. LogTypeDescLength = 0;
  1234. LogHeaderDescExists = 0;
  1235. }
  1236. SizeNeeded = FIELD_OFFSET(SMBIOS_EVENTLOG_INFO, VariableData) +
  1237. LogTypeDescLength +
  1238. LogAreaLength;
  1239. if (*BufferSize >= SizeNeeded)
  1240. {
  1241. EventlogInfo = (PSMBIOS_EVENTLOG_INFO)Buffer;
  1242. EventlogInfo->LogTypeDescLength = LogTypeDescLength;
  1243. EventlogInfo->LogHeaderDescExists = LogHeaderDescExists;
  1244. EventlogInfo->Reserved = 0;
  1245. EventlogArea = &EventlogInfo->VariableData[LogTypeDescLength];
  1246. if (LogHeaderDescExists == 1)
  1247. {
  1248. //
  1249. // if log header descriptors exist (smbios 2.1+) then copy
  1250. // rest of smbios header plus log type descriptors
  1251. //
  1252. RtlCopyMemory(&EventlogInfo->LogAreaLength,
  1253. &SystemEventlog->LogAreaLength,
  1254. (SystemEventlog->Length -
  1255. FIELD_OFFSET(SMBIOS_SYSTEM_EVENTLOG_STRUCT,
  1256. LogAreaLength)));
  1257. } else {
  1258. //
  1259. // if no log header descriptors then just copy smbios 2.0
  1260. // defined fields and zero out rest of structure
  1261. //
  1262. RtlCopyMemory(&EventlogInfo->LogAreaLength,
  1263. &SystemEventlog->LogAreaLength,
  1264. FIELD_OFFSET(SMBIOS_EVENTLOG_INFO, LogHeaderFormat) -
  1265. FIELD_OFFSET(SMBIOS_EVENTLOG_INFO, LogAreaLength));
  1266. *((PUSHORT)&EventlogInfo->LogHeaderFormat) = 0;
  1267. EventlogInfo->LengthEachLogTypeDesc = 0;
  1268. }
  1269. WmipUnmapSMBiosStructure(MapAddress, MapSize);
  1270. switch(AccessMethod)
  1271. {
  1272. case ACCESS_METHOD_MEMMAP:
  1273. {
  1274. //
  1275. // Eventlog is maintained in physical memory
  1276. //
  1277. PHYSICAL_ADDRESS PhysicalAddress;
  1278. PUCHAR EventlogVirtualAddress;
  1279. PhysicalAddress.HighPart = 0;
  1280. PhysicalAddress.LowPart = AccessMethodAddress.AccessMethodAddress.PhysicalAddress32;
  1281. EventlogVirtualAddress = MmMapIoSpace(PhysicalAddress,
  1282. LogAreaLength,
  1283. MmCached);
  1284. if ((EventlogArea != NULL) &&
  1285. (EventlogVirtualAddress != NULL))
  1286. {
  1287. RtlCopyMemory(EventlogArea,
  1288. EventlogVirtualAddress,
  1289. LogAreaLength);
  1290. MmUnmapIoSpace(EventlogVirtualAddress,
  1291. LogAreaLength);
  1292. Status = STATUS_SUCCESS;
  1293. } else {
  1294. Status = STATUS_UNSUCCESSFUL;
  1295. }
  1296. break;
  1297. };
  1298. case ACCESS_METHOD_INDEXIO_1:
  1299. {
  1300. // break;
  1301. };
  1302. case ACCESS_METHOD_INDEXIO_2:
  1303. {
  1304. // break;
  1305. };
  1306. case ACCESS_METHOD_INDEXIO_3:
  1307. {
  1308. // break;
  1309. };
  1310. case ACCESS_METHOD_GPNV:
  1311. {
  1312. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: SMBIOS Eventlog access method GPNV %x\n",
  1313. AccessMethod));
  1314. Status = STATUS_UNSUCCESSFUL;
  1315. break;
  1316. };
  1317. default:
  1318. {
  1319. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: SMBIOS Eventlog access method %x\n",
  1320. AccessMethod));
  1321. WmipAssert(FALSE);
  1322. Status = STATUS_UNSUCCESSFUL;
  1323. }
  1324. };
  1325. Status = STATUS_SUCCESS;
  1326. } else {
  1327. WmipUnmapSMBiosStructure(MapAddress, MapSize);
  1328. Status = STATUS_BUFFER_TOO_SMALL;
  1329. }
  1330. *BufferSize = SizeNeeded;
  1331. }
  1332. return(Status);
  1333. }
  1334. NTSTATUS
  1335. WmipDockUndockEventCallback(
  1336. IN PVOID NoificationStructure,
  1337. IN PVOID Context
  1338. )
  1339. {
  1340. PAGED_CODE();
  1341. //
  1342. // if SMBIOS data is obtained via the table in the bios, then reset
  1343. // the flag to indicate that we need to rescan for the table. It is
  1344. // possible that a dock or undock could have changed the data. If we
  1345. // obtained the data from ntdetect then there is nothing we can do
  1346. // since we cannot call the bios.
  1347. if (WmipSMBiosTablePhysicalAddress.QuadPart != 0)
  1348. {
  1349. WmipEnterSMCritSection();
  1350. WmipSMBiosChecked = FALSE;
  1351. WmipLeaveSMCritSection();
  1352. }
  1353. return(STATUS_SUCCESS);
  1354. }
  1355. #endif