1 /*
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)
7 */
8
9 /* INCLUDES *****************************************************************/
10
11 #include <ntoskrnl.h>
12 #include <wmiguid.h>
13 #include <wmidata.h>
14 #include <wmistr.h>
15
16 #include "wmip.h"
17
18 #define NDEBUG
19 #include <debug.h>
20
21
22 /* FUNCTIONS *****************************************************************/
23
24 typedef struct _SMBIOS21_ENTRY_POINT
25 {
26 CHAR AnchorString[4];
27 UCHAR Checksum;
28 UCHAR Length;
29 UCHAR MajorVersion;
30 UCHAR MinorVersion;
31 USHORT MaxStructureSize;
32 UCHAR EntryPointRevision;
33 CHAR FormattedArea[5];
34 CHAR AnchorString2[5];
35 UCHAR Checksum2;
36 USHORT TableLength;
37 ULONG TableAddress;
38 USHORT NumberOfStructures;
39 UCHAR BCDRevision;
40 } SMBIOS21_ENTRY_POINT, *PSMBIOS21_ENTRY_POINT;
41
42 typedef struct _SMBIOS30_ENTRY_POINT
43 {
44 CHAR AnchorString[5];
45 UCHAR Checksum;
46 UCHAR Length;
47 UCHAR MajorVersion;
48 UCHAR MinorVersion;
49 UCHAR Docref;
50 UCHAR Revision;
51 UCHAR Reserved;
52 ULONG TableMaxSize;
53 ULONG64 TableAddress;
54 } SMBIOS30_ENTRY_POINT, *PSMBIOS30_ENTRY_POINT;
55
56 static
57 BOOLEAN
GetEntryPointData(_In_ const UCHAR * EntryPointAddress,_Out_ PULONG64 TableAddress,_Out_ PULONG TableSize,_Out_ PMSSmBios_RawSMBiosTables BiosTablesHeader)58 GetEntryPointData(
59 _In_ const UCHAR *EntryPointAddress,
60 _Out_ PULONG64 TableAddress,
61 _Out_ PULONG TableSize,
62 _Out_ PMSSmBios_RawSMBiosTables BiosTablesHeader)
63 {
64 PSMBIOS21_ENTRY_POINT EntryPoint21;
65 PSMBIOS30_ENTRY_POINT EntryPoint30;
66 UCHAR Checksum;
67 ULONG i;
68
69 /* Check for SMBIOS 2.1 entry point */
70 EntryPoint21 = (PSMBIOS21_ENTRY_POINT)EntryPointAddress;
71 if (RtlEqualMemory(EntryPoint21->AnchorString, "_SM_", 4))
72 {
73 if (EntryPoint21->Length > 32)
74 return FALSE;
75
76 /* Calculate the checksum */
77 Checksum = 0;
78 for (i = 0; i < EntryPoint21->Length; i++)
79 {
80 Checksum += EntryPointAddress[i];
81 }
82
83 if (Checksum != 0)
84 return FALSE;
85
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;
93 return TRUE;
94 }
95
96 /* Check for SMBIOS 3.0 entry point */
97 EntryPoint30 = (PSMBIOS30_ENTRY_POINT)EntryPointAddress;
98 if (RtlEqualMemory(EntryPoint30->AnchorString, "_SM3_", 5))
99 {
100 if (EntryPoint30->Length > 32)
101 return FALSE;
102
103 /* Calculate the checksum */
104 Checksum = 0;
105 for (i = 0; i < EntryPoint30->Length; i++)
106 {
107 Checksum += EntryPointAddress[i];
108 }
109
110 if (Checksum != 0)
111 return FALSE;
112
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;
120 return TRUE;
121 }
122
123 return FALSE;
124 }
125
126 _At_(*OutTableData, __drv_allocatesMem(Mem))
127 NTSTATUS
128 NTAPI
WmipGetRawSMBiosTableData(_Outptr_opt_result_buffer_ (* OutDataSize)PVOID * OutTableData,_Out_ PULONG OutDataSize)129 WmipGetRawSMBiosTableData(
130 _Outptr_opt_result_buffer_(*OutDataSize) PVOID *OutTableData,
131 _Out_ PULONG OutDataSize)
132 {
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;
141
142 /* This is where the range for the entry point starts */
143 PhysicalAddress.QuadPart = 0xF0000;
144
145 /* Map the range into the system address space */
146 EntryPointMapping = MmMapIoSpace(PhysicalAddress, SearchSize, MmCached);
147 if (EntryPointMapping == NULL)
148 {
149 DPRINT1("Failed to map range for SMBIOS entry point\n");
150 return STATUS_UNSUCCESSFUL;
151 }
152
153 /* Loop the table memory in 16 byte steps */
154 for (Offset = 0; Offset <= (0x10000 - 32); Offset += 16)
155 {
156 /* Check if we have an entry point here and get it's data */
157 if (GetEntryPointData(EntryPointMapping + Offset,
158 &TableAddress,
159 &TableSize,
160 &BiosTablesHeader))
161 {
162 break;
163 }
164 }
165
166 /* Unmap the entry point */
167 MmUnmapIoSpace(EntryPointMapping, SearchSize);
168
169 /* Did we find anything */
170 if (TableAddress == 0)
171 {
172 DPRINT1("Could not find the SMBIOS entry point\n");
173 return STATUS_NOT_FOUND;
174 }
175
176 /* Check if the caller asked for the buffer */
177 if (OutTableData != NULL)
178 {
179 /* Allocate a buffer for the result */
180 BiosTables = ExAllocatePoolWithTag(PagedPool,
181 HeaderSize + TableSize,
182 'BTMS');
183 if (BiosTables == NULL)
184 {
185 DPRINT1("Failed to allocate %lu bytes for the SMBIOS table\n",
186 HeaderSize + TableSize);
187 return STATUS_INSUFFICIENT_RESOURCES;
188 }
189
190 /* Copy the header */
191 RtlCopyMemory(BiosTables, &BiosTablesHeader, HeaderSize);
192
193 /* This is where the table is */
194 PhysicalAddress.QuadPart = TableAddress;
195
196 /* Map the table into the system address space */
197 TableMapping = MmMapIoSpace(PhysicalAddress, TableSize, MmCached);
198 if (TableMapping == NULL)
199 {
200 ExFreePoolWithTag(BiosTables, 'BTMS');
201 return STATUS_UNSUCCESSFUL;
202 }
203
204 /* Copy the table */
205 RtlCopyMemory((PUCHAR)BiosTables + HeaderSize, TableMapping, TableSize);
206
207 /* Unmap the table */
208 MmUnmapIoSpace(TableMapping, TableSize);
209
210 *OutTableData = BiosTables;
211 }
212
213 *OutDataSize = HeaderSize + TableSize;
214 return STATUS_SUCCESS;
215 }
216
217
218 NTSTATUS
219 NTAPI
WmipQueryRawSMBiosTables(_Inout_ ULONG * InOutBufferSize,_Out_opt_ PVOID OutBuffer)220 WmipQueryRawSMBiosTables(
221 _Inout_ ULONG *InOutBufferSize,
222 _Out_opt_ PVOID OutBuffer)
223 {
224 NTSTATUS Status;
225 PVOID TableData = NULL;
226 ULONG TableSize, ResultSize;
227 PWNODE_ALL_DATA AllData;
228
229 /* Get the table data */
230 Status = WmipGetRawSMBiosTableData(OutBuffer ? &TableData : NULL, &TableSize);
231 if (!NT_SUCCESS(Status))
232 {
233 DPRINT1("WmipGetRawSMBiosTableData failed: 0x%08lx\n", Status);
234 return Status;
235 }
236
237 ResultSize = sizeof(WNODE_ALL_DATA) + TableSize;
238
239 /* Check if the caller provided a buffer */
240 if ((OutBuffer != NULL) && (*InOutBufferSize != 0))
241 {
242 /* Check if the buffer is large enough */
243 if (*InOutBufferSize < ResultSize)
244 {
245 DPRINT1("Buffer too small. Got %lu, need %lu\n",
246 *InOutBufferSize, ResultSize);
247 return STATUS_BUFFER_TOO_SMALL;
248 }
249
250 /// FIXME: most of this is fubar
251 AllData = OutBuffer;
252 AllData->WnodeHeader.BufferSize = ResultSize;
253 AllData->WnodeHeader.ProviderId = 0;
254 AllData->WnodeHeader.Version = 0;
255 AllData->WnodeHeader.Linkage = 0; // last entry
256 //AllData->WnodeHeader.CountLost;
257 AllData->WnodeHeader.KernelHandle = NULL;
258 //AllData->WnodeHeader.TimeStamp;
259 AllData->WnodeHeader.Guid = MSSmBios_RawSMBiosTables_GUID;
260 //AllData->WnodeHeader.ClientContext;
261 AllData->WnodeHeader.Flags = WNODE_FLAG_FIXED_INSTANCE_SIZE;
262 AllData->DataBlockOffset = sizeof(WNODE_ALL_DATA);
263 AllData->InstanceCount = 1;
264 //AllData->OffsetInstanceNameOffsets;
265 AllData->FixedInstanceSize = TableSize;
266
267 RtlCopyMemory(AllData + 1, TableData, TableSize);
268 }
269
270 /* Set the size */
271 *InOutBufferSize = ResultSize;
272
273 /* Free the table buffer */
274 if (TableData != NULL)
275 {
276 ExFreePoolWithTag(TableData, 'BTMS');
277 }
278
279 return STATUS_SUCCESS;
280 }
281
282