diff --git a/reactos/ntoskrnl/ntos.cmake b/reactos/ntoskrnl/ntos.cmake index 5445101924d..6c42c3bc44b 100644 --- a/reactos/ntoskrnl/ntos.cmake +++ b/reactos/ntoskrnl/ntos.cmake @@ -270,6 +270,7 @@ list(APPEND SOURCE ${REACTOS_SOURCE_DIR}/ntoskrnl/se/token.c ${REACTOS_SOURCE_DIR}/ntoskrnl/vf/driver.c ${REACTOS_SOURCE_DIR}/ntoskrnl/wmi/guidobj.c + ${REACTOS_SOURCE_DIR}/ntoskrnl/wmi/smbios.c ${REACTOS_SOURCE_DIR}/ntoskrnl/wmi/wmi.c ${REACTOS_SOURCE_DIR}/ntoskrnl/wmi/wmidrv.c) diff --git a/reactos/ntoskrnl/wmi/guidobj.c b/reactos/ntoskrnl/wmi/guidobj.c index 301b457192f..b1e5c91d5fe 100644 --- a/reactos/ntoskrnl/wmi/guidobj.c +++ b/reactos/ntoskrnl/wmi/guidobj.c @@ -167,22 +167,13 @@ WmipGUIDFromString( static NTSTATUS WmipCreateGuidObject( - _In_ PUNICODE_STRING GuidString, + _In_ const GUID *Guid, _Out_ PWMIP_GUID_OBJECT *OutGuidObject) { OBJECT_ATTRIBUTES ObjectAttributes; - GUID Guid; PWMIP_GUID_OBJECT GuidObject; NTSTATUS Status; - /* Convert the string into a GUID structure */ - Status = WmipGUIDFromString(GuidString, &Guid); - if (!NT_SUCCESS(Status)) - { - DPRINT1("WMI: Invalid uuid format for guid '%wZ'\n", GuidString); - return Status; - } - /* Initialize object attributes for an unnamed object */ InitializeObjectAttributes(&ObjectAttributes, NULL, @@ -207,7 +198,7 @@ WmipCreateGuidObject( } RtlZeroMemory(GuidObject, sizeof(*GuidObject)); - GuidObject->Guid = Guid; + GuidObject->Guid = *Guid; *OutGuidObject = GuidObject; @@ -217,37 +208,22 @@ WmipCreateGuidObject( NTSTATUS NTAPI WmipOpenGuidObject( - POBJECT_ATTRIBUTES ObjectAttributes, - ACCESS_MASK DesiredAccess, - KPROCESSOR_MODE AccessMode, - PHANDLE OutGuidObjectHandle, - PVOID *OutGuidObject) + _In_ LPCGUID Guid, + _In_ ACCESS_MASK DesiredAccess, + _In_ KPROCESSOR_MODE AccessMode, + _Out_ PHANDLE OutGuidObjectHandle, + _Outptr_ PVOID *OutGuidObject) { - static UNICODE_STRING Prefix = RTL_CONSTANT_STRING(L"\\WmiGuid\\"); - UNICODE_STRING GuidString; - ULONG HandleAttributes; PWMIP_GUID_OBJECT GuidObject; + ULONG HandleAttributes; NTSTATUS Status; - PAGED_CODE(); - - /* Check if we have the expected prefix */ - if (!RtlPrefixUnicodeString(&Prefix, ObjectAttributes->ObjectName, FALSE)) - { - DPRINT1("WMI: Invalid prefix for guid object '%wZ'\n", - ObjectAttributes->ObjectName); - return STATUS_INVALID_PARAMETER; - } - - /* Extract the GUID string */ - GuidString = *ObjectAttributes->ObjectName; - GuidString.Buffer += Prefix.Length / sizeof(WCHAR); - GuidString.Length -= Prefix.Length; /* Create the GUID object */ - Status = WmipCreateGuidObject(&GuidString, &GuidObject); + Status = WmipCreateGuidObject(Guid, &GuidObject); if (!NT_SUCCESS(Status)) { DPRINT1("Failed to create GUID object: 0x%lx\n", Status); + *OutGuidObject = NULL; return Status; } @@ -266,6 +242,7 @@ WmipOpenGuidObject( { DPRINT1("ObOpenObjectByPointer failed: 0x%lx\n", Status); ObfDereferenceObject(GuidObject); + GuidObject = NULL; } *OutGuidObject = GuidObject; @@ -273,3 +250,46 @@ WmipOpenGuidObject( return Status; } +NTSTATUS +NTAPI +WmipOpenGuidObjectByName( + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ ACCESS_MASK DesiredAccess, + _In_ KPROCESSOR_MODE AccessMode, + _Out_ PHANDLE OutGuidObjectHandle, + _Outptr_ PVOID *OutGuidObject) +{ + static UNICODE_STRING Prefix = RTL_CONSTANT_STRING(L"\\WmiGuid\\"); + UNICODE_STRING GuidString; + NTSTATUS Status; + GUID Guid; + PAGED_CODE(); + + /* Check if we have the expected prefix */ + if (!RtlPrefixUnicodeString(&Prefix, ObjectAttributes->ObjectName, FALSE)) + { + DPRINT1("WMI: Invalid prefix for guid object '%wZ'\n", + ObjectAttributes->ObjectName); + return STATUS_INVALID_PARAMETER; + } + + /* Extract the GUID string */ + GuidString = *ObjectAttributes->ObjectName; + GuidString.Buffer += Prefix.Length / sizeof(WCHAR); + GuidString.Length -= Prefix.Length; + + /* Convert the string into a GUID structure */ + Status = WmipGUIDFromString(&GuidString, &Guid); + if (!NT_SUCCESS(Status)) + { + DPRINT1("WMI: Invalid uuid format for guid '%wZ'\n", GuidString); + return Status; + } + + return WmipOpenGuidObject(&Guid, + DesiredAccess, + AccessMode, + OutGuidObjectHandle, + OutGuidObject); +} + diff --git a/reactos/ntoskrnl/wmi/smbios.c b/reactos/ntoskrnl/wmi/smbios.c new file mode 100644 index 00000000000..84c7ef0f4ad --- /dev/null +++ b/reactos/ntoskrnl/wmi/smbios.c @@ -0,0 +1,279 @@ +/* + * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory + * FILE: ntoskrnl/io/wmi.c + * PURPOSE: I/O Windows Management Instrumentation (WMI) Support + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) + */ + +/* INCLUDES *****************************************************************/ + +#include +#include +#include +#include + +#include "wmip.h" + +#define NDEBUG +#include + + +/* FUNCTIONS *****************************************************************/ + +typedef struct _SMBIOS21_ENTRY_POINT +{ + CHAR AnchorString[4]; + UCHAR Checksum; + UCHAR Length; + UCHAR MajorVersion; + UCHAR MinorVersion; + USHORT MaxStructureSize; + UCHAR EntryPointRevision; + CHAR FormattedArea[5]; + CHAR AnchorString2[5]; + UCHAR Checksum2; + USHORT TableLength; + ULONG TableAddress; + USHORT NumberOfStructures; + UCHAR BCDRevision; +} SMBIOS21_ENTRY_POINT, *PSMBIOS21_ENTRY_POINT; + +typedef struct _SMBIOS30_ENTRY_POINT +{ + CHAR AnchorString[5]; + UCHAR Checksum; + UCHAR Length; + UCHAR MajorVersion; + UCHAR MinorVersion; + UCHAR Docref; + UCHAR Revision; + UCHAR Reserved; + ULONG TableMaxSize; + ULONG64 TableAddress; +} SMBIOS30_ENTRY_POINT, *PSMBIOS30_ENTRY_POINT; + +static +BOOLEAN +GetEntryPointData( + _In_ const UCHAR *EntryPointAddress, + _Out_ PULONG64 TableAddress, + _Out_ PULONG TableSize, + _Out_ PMSSmBios_RawSMBiosTables BiosTablesHeader) +{ + PSMBIOS21_ENTRY_POINT EntryPoint21; + PSMBIOS30_ENTRY_POINT EntryPoint30; + UCHAR Checksum; + ULONG i; + + /* Check for SMBIOS 2.1 entry point */ + EntryPoint21 = (PSMBIOS21_ENTRY_POINT)EntryPointAddress; + if (RtlEqualMemory(EntryPoint21->AnchorString, "_SM_", 4)) + { + if (EntryPoint21->Length > 32) + return FALSE; + + /* Calculate the checksum */ + Checksum = 0; + for (i = 0; i < EntryPoint21->Length; i++) + { + Checksum += EntryPointAddress[i]; + } + + if (Checksum != 0) + return FALSE; + + *TableAddress = EntryPoint21->TableAddress; + *TableSize = EntryPoint21->TableLength; + BiosTablesHeader->Used20CallingMethod = 0; + BiosTablesHeader->SmbiosMajorVersion = EntryPoint21->MajorVersion; + BiosTablesHeader->SmbiosMinorVersion = EntryPoint21->MinorVersion; + BiosTablesHeader->DmiRevision = 2; + BiosTablesHeader->Size = EntryPoint21->TableLength; + return TRUE; + } + + /* Check for SMBIOS 3.0 entry point */ + EntryPoint30 = (PSMBIOS30_ENTRY_POINT)EntryPointAddress; + if (RtlEqualMemory(EntryPoint30->AnchorString, "_SM3_", 5)) + { + if (EntryPoint30->Length > 32) + return FALSE; + + /* Calculate the checksum */ + Checksum = 0; + for (i = 0; i < EntryPoint30->Length; i++) + { + Checksum += EntryPointAddress[i]; + } + + if (Checksum != 0) + return FALSE; + + *TableAddress = EntryPoint30->TableAddress; + *TableSize = EntryPoint30->TableMaxSize; + BiosTablesHeader->Used20CallingMethod = 0; + BiosTablesHeader->SmbiosMajorVersion = EntryPoint30->MajorVersion; + BiosTablesHeader->SmbiosMinorVersion = EntryPoint30->MinorVersion; + BiosTablesHeader->DmiRevision = 3; + BiosTablesHeader->Size = EntryPoint30->TableMaxSize; + return TRUE; + } + + return FALSE; +} + +_At_(*OutTableData, __drv_allocatesMem(Mem)) +NTSTATUS +NTAPI +WmipGetRawSMBiosTableData( + _Outptr_opt_result_buffer_(*OutDataSize) PVOID *OutTableData, + _Out_ PULONG OutDataSize) +{ + static const SIZE_T SearchSize = 0x10000; + static const ULONG HeaderSize = FIELD_OFFSET(MSSmBios_RawSMBiosTables, SMBiosData); + PHYSICAL_ADDRESS PhysicalAddress; + PUCHAR EntryPointMapping; + MSSmBios_RawSMBiosTables BiosTablesHeader; + PVOID BiosTables, TableMapping; + ULONG Offset, TableSize; + ULONG64 TableAddress = 0; + + /* This is where the range for the entry point starts */ + PhysicalAddress.QuadPart = 0xF0000; + + /* Map the range into the system address space */ + EntryPointMapping = MmMapIoSpace(PhysicalAddress, SearchSize, MmCached); + if (EntryPointMapping == NULL) + { + DPRINT1("Failed to map range for SMBIOS entry point\n"); + return STATUS_UNSUCCESSFUL; + } + + /* Loop the table memory in 16 byte steps */ + for (Offset = 0; Offset <= (0x10000 - 32); Offset += 16) + { + /* Check if we have an entry point here and get it's data */ + if (GetEntryPointData(EntryPointMapping + Offset, + &TableAddress, + &TableSize, + &BiosTablesHeader)) + { + break; + } + } + + /* Unmap the entry point */ + MmUnmapIoSpace(EntryPointMapping, SearchSize); + + /* Did we find anything */ + if (TableAddress == 0) + { + DPRINT1("Could not find the SMBIOS entry point\n"); + return STATUS_NOT_FOUND; + } + + /* Check if the caller asked for the buffer */ + if (OutTableData != NULL) + { + /* Allocate a buffer for the result */ + BiosTables = ExAllocatePoolWithTag(PagedPool, + HeaderSize + TableSize, + 'BTMS'); + if (BiosTables == NULL) + { + DPRINT1("Failed to allocate %lu bytes for the SMBIOS table\n"); + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* Copy the header */ + RtlCopyMemory(BiosTables, &BiosTablesHeader, HeaderSize); + + /* This is where the table is */ + PhysicalAddress.QuadPart = TableAddress; + + /* Map the table into the system address space */ + TableMapping = MmMapIoSpace(PhysicalAddress, TableSize, MmCached); + if (TableMapping == NULL) + { + return STATUS_UNSUCCESSFUL; + } + + /* Copy the table */ + RtlCopyMemory((PUCHAR)BiosTables + HeaderSize, TableMapping, TableSize); + + /* Unmap the table */ + MmUnmapIoSpace(TableMapping, TableSize); + + *OutTableData = BiosTables; + } + + *OutDataSize = HeaderSize + TableSize; + return STATUS_SUCCESS; +} + + +NTSTATUS +NTAPI +WmipQueryRawSMBiosTables( + _Inout_ ULONG *InOutBufferSize, + _Out_opt_ PVOID OutBuffer) +{ + NTSTATUS Status; + PVOID TableData = NULL; + ULONG TableSize, ResultSize; + PWNODE_ALL_DATA AllData; + + /* Get the table data */ + Status = WmipGetRawSMBiosTableData(OutBuffer ? &TableData : NULL, &TableSize); + if (!NT_SUCCESS(Status)) + { + DPRINT1("WmipGetRawSMBiosTableData failed: 0x08lx\n", Status); + return Status; + } + + ResultSize = sizeof(WNODE_ALL_DATA) + TableSize; + + /* Check if the caller provided a buffer */ + if ((OutBuffer != NULL) && (*InOutBufferSize != 0)) + { + /* Check if the buffer is large enough */ + if (*InOutBufferSize < ResultSize) + { + DPRINT1("Buffer too small. Got %lu, need %lu\n", + *InOutBufferSize, ResultSize); + return STATUS_BUFFER_TOO_SMALL; + } + + /// FIXME: most of this is fubar + AllData = OutBuffer; + AllData->WnodeHeader.BufferSize = ResultSize; + AllData->WnodeHeader.ProviderId = 0; + AllData->WnodeHeader.Version = 0; + AllData->WnodeHeader.Linkage = 0; // last entry + //AllData->WnodeHeader.CountLost; + AllData->WnodeHeader.KernelHandle = NULL; + //AllData->WnodeHeader.TimeStamp; + AllData->WnodeHeader.Guid = MSSmBios_RawSMBiosTables_GUID; + AllData->WnodeHeader.ClientContext; + AllData->WnodeHeader.Flags = WNODE_FLAG_FIXED_INSTANCE_SIZE; + AllData->DataBlockOffset = sizeof(WNODE_ALL_DATA); + AllData->InstanceCount = 1; + AllData->OffsetInstanceNameOffsets; + AllData->FixedInstanceSize = TableSize; + + RtlCopyMemory(AllData + 1, TableData, TableSize); + } + + /* Set the size */ + *InOutBufferSize = ResultSize; + + /* Free the table buffer */ + if (TableData != NULL) + { + ExFreePoolWithTag(TableData, 'BTMS'); + } + + return STATUS_SUCCESS; +} + diff --git a/reactos/ntoskrnl/wmi/wmi.c b/reactos/ntoskrnl/wmi/wmi.c index 02bd1b092e0..2662278f42c 100644 --- a/reactos/ntoskrnl/wmi/wmi.c +++ b/reactos/ntoskrnl/wmi/wmi.c @@ -9,6 +9,11 @@ /* INCLUDES *****************************************************************/ #include +#define INITGUID +#include +#include +#include + #include "wmip.h" #define NDEBUG @@ -106,12 +111,28 @@ IoWMIWriteEvent(IN PVOID WnodeEventItem) */ NTSTATUS NTAPI -IoWMIOpenBlock(IN LPCGUID DataBlockGuid, - IN ULONG DesiredAccess, - OUT PVOID *DataBlockObject) +IoWMIOpenBlock( + _In_ LPCGUID DataBlockGuid, + _In_ ULONG DesiredAccess, + _Out_ PVOID *DataBlockObject) { - UNIMPLEMENTED; - return STATUS_NOT_IMPLEMENTED; + HANDLE GuidObjectHandle; + NTSTATUS Status; + + /* Open the GIOD object */ + Status = WmipOpenGuidObject(DataBlockGuid, + DesiredAccess, + KernelMode, + &GuidObjectHandle, + DataBlockObject); + if (!NT_SUCCESS(Status)) + { + DPRINT1("WmipOpenGuidObject failed: 0x%lx\n", Status); + return Status; + } + + + return STATUS_SUCCESS; } /* @@ -119,12 +140,39 @@ IoWMIOpenBlock(IN LPCGUID DataBlockGuid, */ NTSTATUS NTAPI -IoWMIQueryAllData(IN PVOID DataBlockObject, - IN OUT ULONG *InOutBufferSize, - OUT PVOID OutBuffer) +IoWMIQueryAllData( + IN PVOID DataBlockObject, + IN OUT ULONG *InOutBufferSize, + OUT PVOID OutBuffer) { - UNIMPLEMENTED; - return STATUS_NOT_IMPLEMENTED; + PWMIP_GUID_OBJECT GuidObject; + NTSTATUS Status; + + + Status = ObReferenceObjectByPointer(DataBlockObject, + WMIGUID_QUERY, + WmipGuidObjectType, + KernelMode); + if (!NT_SUCCESS(Status)) + { + return Status; + } + + GuidObject = DataBlockObject; + + /* Huge HACK! */ + if (IsEqualGUID(&GuidObject->Guid, &MSSmBios_RawSMBiosTables_GUID)) + { + Status = WmipQueryRawSMBiosTables(InOutBufferSize, OutBuffer); + } + else + { + Status = STATUS_NOT_SUPPORTED; + } + + ObDereferenceObject(DataBlockObject); + + return Status; } /* diff --git a/reactos/ntoskrnl/wmi/wmidrv.c b/reactos/ntoskrnl/wmi/wmidrv.c index 8290a370065..838199c5788 100644 --- a/reactos/ntoskrnl/wmi/wmidrv.c +++ b/reactos/ntoskrnl/wmi/wmidrv.c @@ -210,14 +210,14 @@ WmipRegisterGuids( } /* Open a new GUID object */ - Status = WmipOpenGuidObject(&LocalObjectAttributes, - SPECIFIC_RIGHTS_ALL, - PreviousMode, - &GuidObjectHandle, - &GuidObject); + Status = WmipOpenGuidObjectByName(&LocalObjectAttributes, + SPECIFIC_RIGHTS_ALL, + PreviousMode, + &GuidObjectHandle, + &GuidObject); if (!NT_SUCCESS(Status)) { - DPRINT1("WmipOpenGuidObject failed: 0x%lx\n", Status); + DPRINT1("WmipOpenGuidObjectByName failed: 0x%lx\n", Status); return Status; } @@ -409,14 +409,14 @@ WmipOpenGuidForEvents( } /* Open a new GUID object */ - Status = WmipOpenGuidObject(&LocalObjectAttributes, - OpenGuidForEvents->DesiredAccess, - PreviousMode, - &GuidObjectHandle, - &GuidObject); + Status = WmipOpenGuidObjectByName(&LocalObjectAttributes, + OpenGuidForEvents->DesiredAccess, + PreviousMode, + &GuidObjectHandle, + &GuidObject); if (!NT_SUCCESS(Status)) { - DPRINT1("WmipOpenGuidObject failed: 0x%lx\n", Status); + DPRINT1("WmipOpenGuidObjectByName failed: 0x%lx\n", Status); return Status; } diff --git a/reactos/ntoskrnl/wmi/wmip.h b/reactos/ntoskrnl/wmi/wmip.h index 30cd72ccd72..69ecf7d0572 100644 --- a/reactos/ntoskrnl/wmi/wmip.h +++ b/reactos/ntoskrnl/wmi/wmip.h @@ -1,6 +1,8 @@ #pragma once +extern POBJECT_TYPE WmipGuidObjectType; + #define GUID_STRING_LENGTH 36 typedef struct _WMIP_IRP_CONTEXT @@ -32,8 +34,24 @@ WmipInitializeGuidObjectType( NTSTATUS NTAPI WmipOpenGuidObject( - POBJECT_ATTRIBUTES ObjectAttributes, - ACCESS_MASK DesiredAccess, - KPROCESSOR_MODE AccessMode, - PHANDLE OutGuidObjectHandle, - PVOID *OutGuidObject); + _In_ LPCGUID Guid, + _In_ ACCESS_MASK DesiredAccess, + _In_ KPROCESSOR_MODE AccessMode, + _Out_ PHANDLE OutGuidObjectHandle, + _Outptr_ PVOID *OutGuidObject); + +NTSTATUS +NTAPI +WmipOpenGuidObjectByName( + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ ACCESS_MASK DesiredAccess, + _In_ KPROCESSOR_MODE AccessMode, + _Out_ PHANDLE OutGuidObjectHandle, + _Outptr_ PVOID *OutGuidObject); + +NTSTATUS +NTAPI +WmipQueryRawSMBiosTables( + _Inout_ ULONG *InOutBufferSize, + _Out_opt_ PVOID OutBuffer); +