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 return STATUS_INSUFFICIENT_RESOURCES; 187 } 188 189 /* Copy the header */ 190 RtlCopyMemory(BiosTables, &BiosTablesHeader, HeaderSize); 191 192 /* This is where the table is */ 193 PhysicalAddress.QuadPart = TableAddress; 194 195 /* Map the table into the system address space */ 196 TableMapping = MmMapIoSpace(PhysicalAddress, TableSize, MmCached); 197 if (TableMapping == NULL) 198 { 199 ExFreePoolWithTag(BiosTables, 'BTMS'); 200 return STATUS_UNSUCCESSFUL; 201 } 202 203 /* Copy the table */ 204 RtlCopyMemory((PUCHAR)BiosTables + HeaderSize, TableMapping, TableSize); 205 206 /* Unmap the table */ 207 MmUnmapIoSpace(TableMapping, TableSize); 208 209 *OutTableData = BiosTables; 210 } 211 212 *OutDataSize = HeaderSize + TableSize; 213 return STATUS_SUCCESS; 214 } 215 216 217 NTSTATUS 218 NTAPI 219 WmipQueryRawSMBiosTables( 220 _Inout_ ULONG *InOutBufferSize, 221 _Out_opt_ PVOID OutBuffer) 222 { 223 NTSTATUS Status; 224 PVOID TableData = NULL; 225 ULONG TableSize, ResultSize; 226 PWNODE_ALL_DATA AllData; 227 228 /* Get the table data */ 229 Status = WmipGetRawSMBiosTableData(OutBuffer ? &TableData : NULL, &TableSize); 230 if (!NT_SUCCESS(Status)) 231 { 232 DPRINT1("WmipGetRawSMBiosTableData failed: 0x%08lx\n", Status); 233 return Status; 234 } 235 236 ResultSize = sizeof(WNODE_ALL_DATA) + TableSize; 237 238 /* Check if the caller provided a buffer */ 239 if ((OutBuffer != NULL) && (*InOutBufferSize != 0)) 240 { 241 /* Check if the buffer is large enough */ 242 if (*InOutBufferSize < ResultSize) 243 { 244 DPRINT1("Buffer too small. Got %lu, need %lu\n", 245 *InOutBufferSize, ResultSize); 246 return STATUS_BUFFER_TOO_SMALL; 247 } 248 249 /// FIXME: most of this is fubar 250 AllData = OutBuffer; 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; 265 266 RtlCopyMemory(AllData + 1, TableData, TableSize); 267 } 268 269 /* Set the size */ 270 *InOutBufferSize = ResultSize; 271 272 /* Free the table buffer */ 273 if (TableData != NULL) 274 { 275 ExFreePoolWithTag(TableData, 'BTMS'); 276 } 277 278 return STATUS_SUCCESS; 279 } 280 281