xref: /reactos/ntoskrnl/wmi/smbios.c (revision 1734f297)
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
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
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
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