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