2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/wmi/smbios.c
5 * PURPOSE: I/O Windows Management Instrumentation (WMI) Support
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
9 /* INCLUDES *****************************************************************/
22 /* FUNCTIONS *****************************************************************/
24 typedef struct _SMBIOS21_ENTRY_POINT
31 USHORT MaxStructureSize
;
32 UCHAR EntryPointRevision
;
33 CHAR FormattedArea
[5];
34 CHAR AnchorString2
[5];
38 USHORT NumberOfStructures
;
40 } SMBIOS21_ENTRY_POINT
, *PSMBIOS21_ENTRY_POINT
;
42 typedef struct _SMBIOS30_ENTRY_POINT
54 } SMBIOS30_ENTRY_POINT
, *PSMBIOS30_ENTRY_POINT
;
59 _In_
const UCHAR
*EntryPointAddress
,
60 _Out_ PULONG64 TableAddress
,
61 _Out_ PULONG TableSize
,
62 _Out_ PMSSmBios_RawSMBiosTables BiosTablesHeader
)
64 PSMBIOS21_ENTRY_POINT EntryPoint21
;
65 PSMBIOS30_ENTRY_POINT EntryPoint30
;
69 /* Check for SMBIOS 2.1 entry point */
70 EntryPoint21
= (PSMBIOS21_ENTRY_POINT
)EntryPointAddress
;
71 if (RtlEqualMemory(EntryPoint21
->AnchorString
, "_SM_", 4))
73 if (EntryPoint21
->Length
> 32)
76 /* Calculate the checksum */
78 for (i
= 0; i
< EntryPoint21
->Length
; i
++)
80 Checksum
+= EntryPointAddress
[i
];
86 *TableAddress
= EntryPoint21
->TableAddress
;
87 *TableSize
= EntryPoint21
->TableLength
;
88 BiosTablesHeader
->Used20CallingMethod
= 0;
89 BiosTablesHeader
->SmbiosMajorVersion
= EntryPoint21
->MajorVersion
;
90 BiosTablesHeader
->SmbiosMinorVersion
= EntryPoint21
->MinorVersion
;
91 BiosTablesHeader
->DmiRevision
= 2;
92 BiosTablesHeader
->Size
= EntryPoint21
->TableLength
;
96 /* Check for SMBIOS 3.0 entry point */
97 EntryPoint30
= (PSMBIOS30_ENTRY_POINT
)EntryPointAddress
;
98 if (RtlEqualMemory(EntryPoint30
->AnchorString
, "_SM3_", 5))
100 if (EntryPoint30
->Length
> 32)
103 /* Calculate the checksum */
105 for (i
= 0; i
< EntryPoint30
->Length
; i
++)
107 Checksum
+= EntryPointAddress
[i
];
113 *TableAddress
= EntryPoint30
->TableAddress
;
114 *TableSize
= EntryPoint30
->TableMaxSize
;
115 BiosTablesHeader
->Used20CallingMethod
= 0;
116 BiosTablesHeader
->SmbiosMajorVersion
= EntryPoint30
->MajorVersion
;
117 BiosTablesHeader
->SmbiosMinorVersion
= EntryPoint30
->MinorVersion
;
118 BiosTablesHeader
->DmiRevision
= 3;
119 BiosTablesHeader
->Size
= EntryPoint30
->TableMaxSize
;
126 _At_(*OutTableData
, __drv_allocatesMem(Mem
))
129 WmipGetRawSMBiosTableData(
130 _Outptr_opt_result_buffer_(*OutDataSize
) PVOID
*OutTableData
,
131 _Out_ PULONG OutDataSize
)
133 static const SIZE_T SearchSize
= 0x10000;
134 static const ULONG HeaderSize
= FIELD_OFFSET(MSSmBios_RawSMBiosTables
, SMBiosData
);
135 PHYSICAL_ADDRESS PhysicalAddress
;
136 PUCHAR EntryPointMapping
;
137 MSSmBios_RawSMBiosTables BiosTablesHeader
;
138 PVOID BiosTables
, TableMapping
;
139 ULONG Offset
, TableSize
;
140 ULONG64 TableAddress
= 0;
142 /* This is where the range for the entry point starts */
143 PhysicalAddress
.QuadPart
= 0xF0000;
145 /* Map the range into the system address space */
146 EntryPointMapping
= MmMapIoSpace(PhysicalAddress
, SearchSize
, MmCached
);
147 if (EntryPointMapping
== NULL
)
149 DPRINT1("Failed to map range for SMBIOS entry point\n");
150 return STATUS_UNSUCCESSFUL
;
153 /* Loop the table memory in 16 byte steps */
154 for (Offset
= 0; Offset
<= (0x10000 - 32); Offset
+= 16)
156 /* Check if we have an entry point here and get it's data */
157 if (GetEntryPointData(EntryPointMapping
+ Offset
,
166 /* Unmap the entry point */
167 MmUnmapIoSpace(EntryPointMapping
, SearchSize
);
169 /* Did we find anything */
170 if (TableAddress
== 0)
172 DPRINT1("Could not find the SMBIOS entry point\n");
173 return STATUS_NOT_FOUND
;
176 /* Check if the caller asked for the buffer */
177 if (OutTableData
!= NULL
)
179 /* Allocate a buffer for the result */
180 BiosTables
= ExAllocatePoolWithTag(PagedPool
,
181 HeaderSize
+ TableSize
,
183 if (BiosTables
== NULL
)
185 DPRINT1("Failed to allocate %lu bytes for the SMBIOS table\n");
186 return STATUS_INSUFFICIENT_RESOURCES
;
189 /* Copy the header */
190 RtlCopyMemory(BiosTables
, &BiosTablesHeader
, HeaderSize
);
192 /* This is where the table is */
193 PhysicalAddress
.QuadPart
= TableAddress
;
195 /* Map the table into the system address space */
196 TableMapping
= MmMapIoSpace(PhysicalAddress
, TableSize
, MmCached
);
197 if (TableMapping
== NULL
)
199 ExFreePoolWithTag(BiosTables
, 'BTMS');
200 return STATUS_UNSUCCESSFUL
;
204 RtlCopyMemory((PUCHAR
)BiosTables
+ HeaderSize
, TableMapping
, TableSize
);
206 /* Unmap the table */
207 MmUnmapIoSpace(TableMapping
, TableSize
);
209 *OutTableData
= BiosTables
;
212 *OutDataSize
= HeaderSize
+ TableSize
;
213 return STATUS_SUCCESS
;
219 WmipQueryRawSMBiosTables(
220 _Inout_ ULONG
*InOutBufferSize
,
221 _Out_opt_ PVOID OutBuffer
)
224 PVOID TableData
= NULL
;
225 ULONG TableSize
, ResultSize
;
226 PWNODE_ALL_DATA AllData
;
228 /* Get the table data */
229 Status
= WmipGetRawSMBiosTableData(OutBuffer
? &TableData
: NULL
, &TableSize
);
230 if (!NT_SUCCESS(Status
))
232 DPRINT1("WmipGetRawSMBiosTableData failed: 0x08lx\n", Status
);
236 ResultSize
= sizeof(WNODE_ALL_DATA
) + TableSize
;
238 /* Check if the caller provided a buffer */
239 if ((OutBuffer
!= NULL
) && (*InOutBufferSize
!= 0))
241 /* Check if the buffer is large enough */
242 if (*InOutBufferSize
< ResultSize
)
244 DPRINT1("Buffer too small. Got %lu, need %lu\n",
245 *InOutBufferSize
, ResultSize
);
246 return STATUS_BUFFER_TOO_SMALL
;
249 /// FIXME: most of this is fubar
251 AllData
->WnodeHeader
.BufferSize
= ResultSize
;
252 AllData
->WnodeHeader
.ProviderId
= 0;
253 AllData
->WnodeHeader
.Version
= 0;
254 AllData
->WnodeHeader
.Linkage
= 0; // last entry
255 //AllData->WnodeHeader.CountLost;
256 AllData
->WnodeHeader
.KernelHandle
= NULL
;
257 //AllData->WnodeHeader.TimeStamp;
258 AllData
->WnodeHeader
.Guid
= MSSmBios_RawSMBiosTables_GUID
;
259 //AllData->WnodeHeader.ClientContext;
260 AllData
->WnodeHeader
.Flags
= WNODE_FLAG_FIXED_INSTANCE_SIZE
;
261 AllData
->DataBlockOffset
= sizeof(WNODE_ALL_DATA
);
262 AllData
->InstanceCount
= 1;
263 //AllData->OffsetInstanceNameOffsets;
264 AllData
->FixedInstanceSize
= TableSize
;
266 RtlCopyMemory(AllData
+ 1, TableData
, TableSize
);
270 *InOutBufferSize
= ResultSize
;
272 /* Free the table buffer */
273 if (TableData
!= NULL
)
275 ExFreePoolWithTag(TableData
, 'BTMS');
278 return STATUS_SUCCESS
;