diff options
Diffstat (limited to 'powerlimit/plclient')
| -rw-r--r-- | powerlimit/plclient/README.md | 17 | ||||
| -rw-r--r-- | powerlimit/plclient/plclient.asl | 10 | ||||
| -rw-r--r-- | powerlimit/plclient/plclient.c | 451 | ||||
| -rw-r--r-- | powerlimit/plclient/plclient.h | 95 | ||||
| -rw-r--r-- | powerlimit/plclient/plclient.inf | 83 | ||||
| -rw-r--r-- | powerlimit/plclient/plclient.rc | 11 | ||||
| -rw-r--r-- | powerlimit/plclient/plclient.sln | 35 | ||||
| -rw-r--r-- | powerlimit/plclient/plclient.vcxproj | 123 | ||||
| -rw-r--r-- | powerlimit/plclient/plclient.vcxproj.filters | 47 | ||||
| -rw-r--r-- | powerlimit/plclient/powerlimitclient_drvinterface.h | 58 | ||||
| -rw-r--r-- | powerlimit/plclient/wdf.c | 477 |
11 files changed, 1407 insertions, 0 deletions
diff --git a/powerlimit/plclient/README.md b/powerlimit/plclient/README.md new file mode 100644 index 00000000..8ee71011 --- /dev/null +++ b/powerlimit/plclient/README.md @@ -0,0 +1,17 @@ +--- +page_type: sample +description: "Demonstrates a simulated power limit device." +languages: +- cpp +products: +- windows +- windows-wdk +--- + +# plclient - Simulated Power Limit Client Driver + +This sample is a driver for a simulated power limit client device. + +## Universal Windows Driver Compliant + +The plclient sample provides the source code for a power limit device that supports power limit management by the operating system. diff --git a/powerlimit/plclient/plclient.asl b/powerlimit/plclient/plclient.asl new file mode 100644 index 00000000..ce0458df --- /dev/null +++ b/powerlimit/plclient/plclient.asl @@ -0,0 +1,10 @@ +DefinitionBlock ("ACPITABL.DAT", "SSDT", 0x02, "MSFT", "simulatr", 0x1) { + Device (\_SB.SOC0) { + Name (_HID, "PLCL0001") + Name (_UID, 1) + } + Device (\_SB.GPU1) { + Name (_HID, "PLCL0001") + Name (_UID, 2) + } +}
\ No newline at end of file diff --git a/powerlimit/plclient/plclient.c b/powerlimit/plclient/plclient.c new file mode 100644 index 00000000..41676590 --- /dev/null +++ b/powerlimit/plclient/plclient.c @@ -0,0 +1,451 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + plclient.c + +Abstract: + + This module implements power limit related operations for the simulated power + limit client driver. + +--*/ + +//-------------------------------------------------------------------- Includes + +#include "plclient.h" + +//--------------------------------------------------------------------- Pragmas + +#pragma alloc_text(PAGE, InitPowerLimitValues) +#pragma alloc_text(PAGE, CleanupPowerLimitValues) +#pragma alloc_text(PAGE, PLCQueryAttributes) +#pragma alloc_text(PAGE, PLCSetLimits) +#pragma alloc_text(PAGE, PLCQueryLimitValues) + +//------------------------------------------------------------------- Functions + +_Use_decl_annotations_ +NTSTATUS +InitPowerLimitValues ( + PFDO_DATA DevExt + ) + +/*++ + +Routine Description: + + This routine initializes simulated limit values and attributes for the supplied + device extension. + +Parameters Description: + + DevExt - Supplies a pointer to the device extension to be udpated. + +Return Value: + + NTSTATUS. + +--*/ + +{ + + ULONG DomainId; + ULONG Index; + PPOWER_LIMIT_ATTRIBUTES LimitAttributes; + ULONG LimitCount; + PPOWER_LIMIT_VALUE LimitValues; + NTSTATUS Status; + ULONG Type; + + PAGED_CODE(); + + LimitAttributes = NULL; + LimitValues = NULL; + LimitCount = PLCLIENT_DEFAULT_DOMAIN_COUNT * PLCLIENT_DEFAULT_LIMIT_COUNT_PER_DOMAIN; + LimitAttributes = ExAllocatePool2(POOL_FLAG_PAGED, + LimitCount * sizeof(POWER_LIMIT_ATTRIBUTES), + PLCLIENT_TAG); + + LimitValues = ExAllocatePool2(POOL_FLAG_PAGED, + LimitCount * sizeof(POWER_LIMIT_VALUE), + PLCLIENT_TAG); + + if ((LimitAttributes == NULL) || (LimitValues == NULL)) { + Status = STATUS_INSUFFICIENT_RESOURCES; + goto InitPowerLimitValuesEnd; + } + + for (DomainId = 0; DomainId < PLCLIENT_DEFAULT_DOMAIN_COUNT; DomainId += 1) { + for (Type = 0; Type < PLCLIENT_DEFAULT_LIMIT_COUNT_PER_DOMAIN; Type += 1) { + Index = (PLCLIENT_DEFAULT_LIMIT_COUNT_PER_DOMAIN * DomainId) + Type; + + // + // Set init attributes. + // + + LimitAttributes[Index].Type = Type; + LimitAttributes[Index].DomainId = DomainId; + LimitAttributes[Index].MaxValue = PLCLIENT_DEFAULT_MAX_VALUE; + LimitAttributes[Index].MinValue = PLCLIENT_DEFAULT_MIN_VALUE; + LimitAttributes[Index].DefaultACValue = POWER_LIMIT_VALUE_NO_CONTROL; + LimitAttributes[Index].DefaultDCValue = POWER_LIMIT_VALUE_NO_CONTROL; + + if (Type == PowerLimitContinuous) { + LimitAttributes[Index].MinTimeParameter = PLCLIENT_DEFAULT_MIN_VALUE; + LimitAttributes[Index].MaxTimeParameter = PLCLIENT_DEFAULT_MAX_VALUE; + LimitAttributes[Index].Flags.SupportTimeParameter = 1; + } + + // + // Set init values. + // + + LimitValues[Index].Type = Type; + LimitValues[Index].DomainId = DomainId; + LimitValues[Index].TargetValue = POWER_LIMIT_VALUE_NO_CONTROL; + LimitValues[Index].TimeParameter = POWER_LIMIT_VALUE_NO_CONTROL; + } + } + + DevExt->LimitCount = LimitCount; + DevExt->LimitAttributes = LimitAttributes; + DevExt->LimitValues = LimitValues; + LimitAttributes = NULL; + LimitValues = NULL; + Status = STATUS_SUCCESS; + +InitPowerLimitValuesEnd: + if (LimitAttributes != NULL) { + ExFreePoolWithTag(LimitAttributes, PLCLIENT_TAG); + LimitAttributes = NULL; + } + + if (LimitValues != NULL) { + ExFreePoolWithTag(LimitValues, PLCLIENT_TAG); + LimitValues = NULL; + } + + return Status; +} + +_Use_decl_annotations_ +VOID +CleanupPowerLimitValues ( + PFDO_DATA DevExt + ) + +/*++ + +Routine Description: + + This routine cleans up simulated limit values and attributes for the supplied + device extension. + +Parameters Description: + + DevExt - Supplies a pointer to the device extension to be udpated. + +Return Value: + + NTSTATUS. + +--*/ + +{ + + PAGED_CODE(); + + if (DevExt == NULL) { + goto CleanupPowerLimitValuesEnd; + } + + if (DevExt->LimitAttributes != NULL) { + ExFreePoolWithTag(DevExt->LimitAttributes, PLCLIENT_TAG); + DevExt->LimitAttributes = NULL; + } + + if (DevExt->LimitValues != NULL) { + ExFreePoolWithTag(DevExt->LimitValues, PLCLIENT_TAG); + DevExt->LimitValues = NULL; + } + + DevExt->LimitCount = 0; + +CleanupPowerLimitValuesEnd: + return; +} + +_Use_decl_annotations_ +NTSTATUS +PLCQueryAttributes ( + PVOID Context, + ULONG BufferCount, + PVOID Buffer, + PULONG AttributeCount + ) + +/*++ + +Routine Description: + + This is the callback function which returns power limit attributes. + +Parameters Description: + + Context - Supplies a pointer to the device handle. + + BufferCount - Supplies count of Buffer entries. + + Buffer - Supplies a pointer to the buffer to store power limit attributes. + + AttributeCount - Supplies a pointer to save the number of attributes. + +Return Value: + + Returns STATUS_BUFFER_TOO_SMALL if the supplied buffer is not big enough, otherwise + other NTSTATUS values. + +--*/ + +{ + + PFDO_DATA DevExt; + WDFDEVICE DeviceHandle; + BOOLEAN ReleaseLock; + NTSTATUS Status; + + PAGED_CODE(); + + ReleaseLock = FALSE; + if (Context == NULL) { + Status = STATUS_INVALID_PARAMETER; + goto QueryAttributesEnd; + } + + DeviceHandle = (WDFDEVICE)Context; + DevExt = GetDeviceExtension(DeviceHandle); + AcquireGlobalMutex(); + ReleaseLock = TRUE; + if (BufferCount < DevExt->LimitCount) { + if (AttributeCount != NULL) { + *AttributeCount = DevExt->LimitCount; + } + + Status = STATUS_BUFFER_TOO_SMALL; + goto QueryAttributesEnd; + } + + RtlCopyMemory(Buffer, + DevExt->LimitAttributes, + sizeof(POWER_LIMIT_ATTRIBUTES) * DevExt->LimitCount); + + Status = STATUS_SUCCESS; + +QueryAttributesEnd: + if (ReleaseLock != FALSE) { + ReleaseGlobalMutex(); + } + + return Status; +} + +_Use_decl_annotations_ +NTSTATUS +PLCSetLimits ( + PVOID Context, + ULONG ValueCount, + PVOID Values + ) + +/*++ + +Routine Description: + + This is the callback function which takes requests to set power limit values. + +Parameters Description: + + Context - Supplies a pointer to the device handle. + + ValueCount - Supplies count of Value entries. + + Values - Supplies a pointer to the buffer contains values to be updated. + +Return Value: + + NTSTATUS. + +--*/ + +{ + + PPOWER_LIMIT_ATTRIBUTES Attributes; + PFDO_DATA DevExt; + WDFDEVICE DeviceHandle; + ULONG Index; + BOOLEAN ReleaseLock; + NTSTATUS Status; + BOOLEAN Valid; + PPOWER_LIMIT_VALUE ValueBuffer; + ULONG ValueIndex; + + PAGED_CODE(); + + ReleaseLock = FALSE; + if ((Context == NULL) || (ValueCount == 0) || (Values == NULL)) { + Status = STATUS_INVALID_PARAMETER; + goto SetLimitsEnd; + } + + ValueBuffer = (PPOWER_LIMIT_VALUE)Values; + DeviceHandle = (WDFDEVICE)Context; + DevExt = GetDeviceExtension(DeviceHandle); + AcquireGlobalMutex(); + ReleaseLock = TRUE; + + // + // Sanity check on proposed values before update. + // + + if (DevExt->LimitCount < ValueCount) { + Status = STATUS_INVALID_PARAMETER; + goto SetLimitsEnd; + } + + // + // N.B. On a production driver, those values should be used as power limit targets + // for the hardware. + // + + for (Index = 0; Index < ValueCount; Index += 1) { + Valid = FALSE; + for (ValueIndex = 0; ValueIndex < DevExt->LimitCount; ValueIndex += 1) { + if ((ValueBuffer[Index].Type != DevExt->LimitAttributes[ValueIndex].Type) || + (ValueBuffer[Index].DomainId != DevExt->LimitAttributes[ValueIndex].DomainId)) { + + continue; + } + + Attributes = &DevExt->LimitAttributes[ValueIndex]; + if ((ValueBuffer[Index].TargetValue == POWER_LIMIT_VALUE_NO_CONTROL) || + ((ValueBuffer[Index].TargetValue >= Attributes->MinValue) && + (ValueBuffer[Index].TargetValue <= Attributes->MaxValue))) { + + Valid = TRUE; + } + + if (ValueBuffer[Index].TimeParameter != POWER_LIMIT_VALUE_NO_CONTROL) { + if ((Attributes->Flags.SupportTimeParameter != 0) && + (ValueBuffer[Index].TimeParameter >= Attributes->MinTimeParameter) && + (ValueBuffer[Index].TimeParameter <= Attributes->MaxTimeParameter)) { + + Valid = TRUE; + } + } + + break; + } + + // + // N.B. Bail out if this proposed value is not valid. + // + + if (Valid == FALSE) { + Status = STATUS_INVALID_PARAMETER; + goto SetLimitsEnd; + } + } + + for (Index = 0; Index < ValueCount; Index += 1) { + for (ValueIndex = 0; ValueIndex < DevExt->LimitCount; ValueIndex += 1) { + if ((ValueBuffer[Index].Type != DevExt->LimitValues[ValueIndex].Type) || + (ValueBuffer[Index].DomainId != DevExt->LimitValues[ValueIndex].DomainId)) { + + continue; + } + + DevExt->LimitValues[ValueIndex].TargetValue = ValueBuffer[Index].TargetValue; + DevExt->LimitValues[ValueIndex].TimeParameter = ValueBuffer[Index].TimeParameter; + break; + } + } + + Status = STATUS_SUCCESS; + +SetLimitsEnd: + if (ReleaseLock != FALSE) { + ReleaseGlobalMutex(); + } + + return Status; +} + +_Use_decl_annotations_ +NTSTATUS +PLCQueryLimitValues ( + PVOID Context, + ULONG ValueCount, + PVOID Values + ) + +/*++ + +Routine Description: + + This is the callback function which returns power limit values. + +Parameters Description: + + Context - Supplies a pointer to the device handle. + + ValueCount - Supplies count of Value entries. + + Values - Supplies a pointer to the buffer to store power limit values. + +Return Value: + + Returns STATUS_BUFFER_TOO_SMALL if the supplied buffer is not big enough, otherwise + other NTSTATUS values. + +--*/ + +{ + + PFDO_DATA DevExt; + WDFDEVICE DeviceHandle; + BOOLEAN ReleaseLock; + NTSTATUS Status; + + PAGED_CODE(); + + ReleaseLock = FALSE; + if ((Context == NULL) || (ValueCount == 0) || (Values == NULL)){ + Status = STATUS_INVALID_PARAMETER; + goto QueryLimitsEnd; + } + + DeviceHandle = (WDFDEVICE)Context; + DevExt = GetDeviceExtension(DeviceHandle); + AcquireGlobalMutex(); + ReleaseLock = TRUE; + if (ValueCount < DevExt->LimitCount) { + Status = STATUS_BUFFER_TOO_SMALL; + goto QueryLimitsEnd; + } + + RtlCopyMemory(Values, + DevExt->LimitValues, + sizeof(POWER_LIMIT_VALUE) * DevExt->LimitCount); + + Status = STATUS_SUCCESS; + +QueryLimitsEnd: + if (ReleaseLock != FALSE) { + ReleaseGlobalMutex(); + } + + return Status; +} diff --git a/powerlimit/plclient/plclient.h b/powerlimit/plclient/plclient.h new file mode 100644 index 00000000..6e9a7f3f --- /dev/null +++ b/powerlimit/plclient/plclient.h @@ -0,0 +1,95 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + plclient.h + +Abstract: + + This is the header file for the simulated power limit client driver. + +--*/ + +#pragma once + +//-------------------------------------------------------------------- Includes + +#include <ntddk.h> +#include <wdf.h> +#include <ntstrsafe.h> +#include <initguid.h> +#include <wdmguid.h> +#include <poclass.h> +#include <limits.h> +#include "powerlimitclient_drvinterface.h" + +//----------------------------------------------------------------------- Types + +typedef struct { + ULONG LimitCount; + PPOWER_LIMIT_ATTRIBUTES LimitAttributes; + PPOWER_LIMIT_VALUE LimitValues; +} FDO_DATA, *PFDO_DATA; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(FDO_DATA, GetDeviceExtension); + +//----------------------------------------------------------------------- Debug + +#define DebugPrint(l, m, ...) DbgPrintEx(DPFLTR_POWER_ID, l, "[plclient]: "m, __VA_ARGS__) +#define DebugEnter() DebugPrint(PLCLIENT_PRINT_TRACE, "Entering %s", __FUNCTION__) +#define DebugExit() DebugPrint(PLCLIENT_PRINT_TRACE, "Leaving " __FUNCTION__ "\n") +#define DebugExitStatus(_status_) DebugPrint(PLCLIENT_PRINT_TRACE, "Leaving " __FUNCTION__ ": Status=0x%08x\n", _status_) + +#define PLCLIENT_PRINT_ERROR DPFLTR_ERROR_LEVEL +#define PLCLIENT_PRINT_TRACE DPFLTR_TRACE_LEVEL +#define PLCLIENT_PRINT_INFO DPFLTR_INFO_LEVEL + +#define PLCLIENT_TAG 'PLCL' + +//--------------------------------------------------------------------- Globals + +extern WDFWAITLOCK GlobalMutex; + +//------------------------------------------------------------------ Prototypes + +FORCEINLINE +VOID +AcquireGlobalMutex ( + VOID + ) +{ + + WdfWaitLockAcquire(GlobalMutex, 0); + return; +} + +FORCEINLINE +VOID +ReleaseGlobalMutex ( + VOID + ) +{ + + WdfWaitLockRelease(GlobalMutex); + return; +} + +// +// plclient.c +// + +QUERY_POWER_LIMIT_ATTRIBUTES PLCQueryAttributes; +SET_POWER_LIMIT PLCSetLimits; +QUERY_POWER_LIMIT PLCQueryLimitValues; + +NTSTATUS +InitPowerLimitValues ( + _Inout_ PFDO_DATA DevExt + ); + +VOID +CleanupPowerLimitValues ( + _Inout_opt_ PFDO_DATA DevExt + ); diff --git a/powerlimit/plclient/plclient.inf b/powerlimit/plclient/plclient.inf new file mode 100644 index 00000000..136b6761 --- /dev/null +++ b/powerlimit/plclient/plclient.inf @@ -0,0 +1,83 @@ +;/*++ +; +;Copyright (c) Microsoft Corporation All rights Reserved +; +;Module Name: +; +; plclient.inf +; +;Abstract: +; +; INF file for installing simulate power limit client driver. +; +;--*/ + +[Version] +Signature="$WINDOWS NT$" +Class=System +ClassGuid={4D36E97D-E325-11CE-BFC1-08002BE10318} +Provider=%ProviderString% +DriverVer=08/29/2023, 1.00.0000 +CatalogFile=plclient.cat +PnpLockdown=1 + +[DestinationDirs] +DefaultDestDir = 12 + +[SourceDisksNames] +1 = %DiskId1%,,,"" + +[SourceDisksFiles] +plclient.sys = 1,, + +;******************************************** +; Simulated Power Limit Client Install Section +;******************************************** + +[Manufacturer] +%StdMfg%=Standard,NTamd64 +%StdMfg%=Standard,NTarm64 + +[Standard.NTamd64] +%PlCl.DeviceDesc% = PlCl_Device, ACPI\PLCL0001 +%PlCl.DeviceDesc% = PlCl_Device, root\PLCL0001 + +[Standard.NTarm64] +%PlCl.DeviceDesc% = PlCl_Device, ACPI\PLCL0001 +%PlCl.DeviceDesc% = PlCl_Device, root\PLCL0001 + +[PlCl_Device.NT] +CopyFiles=PlCl_Device_Drivers + +[PlCl_Device.NT.HW] +AddReg=PlCl_Device.NT.AddReg + +[PlCl_Device.NT.AddReg] +HKR,,DeviceCharacteristics,0x10001,0x0100 ; Use same security checks on relative opens +HKR,,Security,,"D:P(A;;GA;;;BA)(A;;GA;;;SY)" ; Allow generic-all access to Built-in administrators and Local system + +[PlCl_Device_Drivers] +plclient.sys + +;-------------- Service installation + +[PlCl_Device.NT.Services] +AddService = plclient,%SPSVCINST_ASSOCSERVICE%,PlCl_Service_Inst + +; -------------- plclient driver install sections + +[PlCl_Service_Inst] +DisplayName = %PlCl.SVCDESC% +ServiceType = 1 ; SERVICE_KERNEL_DRIVER +StartType = 3 ; SERVICE_DEMAND_START +ErrorControl = 1 ; SERVICE_ERROR_NORMAL +ServiceBinary = %12%\plclient.sys +LoadOrderGroup = Extended Base + +[Strings] +SPSVCINST_ASSOCSERVICE= 0x00000002 +ProviderString = "TODO-Set-Provider" +StdMfg = "(Standard system devices)" +DiskId1 = "Simulate Power Limit Client Installation Disk #1" +PlCl.DeviceDesc = "Simulate Power Limit Client Device" +PlCl.SVCDESC = "Simulate Power Limit Client Driver" diff --git a/powerlimit/plclient/plclient.rc b/powerlimit/plclient/plclient.rc new file mode 100644 index 00000000..326c61c2 --- /dev/null +++ b/powerlimit/plclient/plclient.rc @@ -0,0 +1,11 @@ +#include <windows.h> + +#include <ntverp.h> + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_DRV_SYSTEM +#define VER_FILEDESCRIPTION_STR "Simulate Power Limit Client Driver" +#define VER_INTERNALNAME_STR "plclient.sys" +#define VER_ORIGINALFILENAME_STR "plclient.sys" + +#include "common.ver" diff --git a/powerlimit/plclient/plclient.sln b/powerlimit/plclient/plclient.sln new file mode 100644 index 00000000..0401b799 --- /dev/null +++ b/powerlimit/plclient/plclient.sln @@ -0,0 +1,35 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.9.34701.34 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "plclient", "plclient.vcxproj", "{D6B30052-9124-44DB-A421-4DEE110B91E2}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|ARM64 = Debug|ARM64 + Debug|x64 = Debug|x64 + Release|ARM64 = Release|ARM64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D6B30052-9124-44DB-A421-4DEE110B91E2}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {D6B30052-9124-44DB-A421-4DEE110B91E2}.Debug|ARM64.Build.0 = Debug|ARM64 + {D6B30052-9124-44DB-A421-4DEE110B91E2}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {D6B30052-9124-44DB-A421-4DEE110B91E2}.Debug|x64.ActiveCfg = Debug|x64 + {D6B30052-9124-44DB-A421-4DEE110B91E2}.Debug|x64.Build.0 = Debug|x64 + {D6B30052-9124-44DB-A421-4DEE110B91E2}.Debug|x64.Deploy.0 = Debug|x64 + {D6B30052-9124-44DB-A421-4DEE110B91E2}.Release|ARM64.ActiveCfg = Release|ARM64 + {D6B30052-9124-44DB-A421-4DEE110B91E2}.Release|ARM64.Build.0 = Release|ARM64 + {D6B30052-9124-44DB-A421-4DEE110B91E2}.Release|ARM64.Deploy.0 = Release|ARM64 + {D6B30052-9124-44DB-A421-4DEE110B91E2}.Release|x64.ActiveCfg = Release|x64 + {D6B30052-9124-44DB-A421-4DEE110B91E2}.Release|x64.Build.0 = Release|x64 + {D6B30052-9124-44DB-A421-4DEE110B91E2}.Release|x64.Deploy.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {810BCAEA-5B6F-43EC-AF83-6B849DF63425} + EndGlobalSection +EndGlobal diff --git a/powerlimit/plclient/plclient.vcxproj b/powerlimit/plclient/plclient.vcxproj new file mode 100644 index 00000000..b1ecc40d --- /dev/null +++ b/powerlimit/plclient/plclient.vcxproj @@ -0,0 +1,123 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|ARM64"> + <Configuration>Debug</Configuration> + <Platform>ARM64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|ARM64"> + <Configuration>Release</Configuration> + <Platform>ARM64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{D6B30052-9124-44DB-A421-4DEE110B91E2}</ProjectGuid> + <TemplateGuid>{1bc93793-694f-48fe-9372-81e2b05556fd}</TemplateGuid> + <TargetFrameworkVersion>v4.5</TargetFrameworkVersion> + <MinimumVisualStudioVersion>12.0</MinimumVisualStudioVersion> + <Configuration>Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">x64</Platform> + <RootNamespace>plclient</RootNamespace> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + <DriverType>KMDF</DriverType> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + <DriverType>KMDF</DriverType> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + <DriverType>KMDF</DriverType> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + <DriverType>KMDF</DriverType> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'"> + <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'"> + <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <DriverSign> + <FileDigestAlgorithm>sha256</FileDigestAlgorithm> + </DriverSign> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <DriverSign> + <FileDigestAlgorithm>sha256</FileDigestAlgorithm> + </DriverSign> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'"> + <DriverSign> + <FileDigestAlgorithm>sha256</FileDigestAlgorithm> + </DriverSign> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'"> + <DriverSign> + <FileDigestAlgorithm>sha256</FileDigestAlgorithm> + </DriverSign> + </ItemDefinitionGroup> + <ItemGroup> + <Inf Include="plclient.inf" /> + </ItemGroup> + <ItemGroup> + <FilesToPackage Include="$(TargetPath)" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="plclient.h" /> + <ClInclude Include="powerlimitclient_drvinterface.h" /> + </ItemGroup> + <ItemGroup> + <ClCompile Include="plclient.c" /> + <ClCompile Include="wdf.c" /> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="plclient.rc" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/powerlimit/plclient/plclient.vcxproj.filters b/powerlimit/plclient/plclient.vcxproj.filters new file mode 100644 index 00000000..391468bc --- /dev/null +++ b/powerlimit/plclient/plclient.vcxproj.filters @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions> + </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + </Filter> + <Filter Include="Resource Files"> + <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier> + <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions> + </Filter> + <Filter Include="Driver Files"> + <UniqueIdentifier>{8E41214B-6785-4CFE-B992-037D68949A14}</UniqueIdentifier> + <Extensions>inf;inv;inx;mof;mc;</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <Inf Include="plclient.inf"> + <Filter>Driver Files</Filter> + </Inf> + </ItemGroup> + <ItemGroup> + <ClInclude Include="plclient.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="powerlimitclient_drvinterface.h"> + <Filter>Header Files</Filter> + </ClInclude> + </ItemGroup> + <ItemGroup> + <ClCompile Include="plclient.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="wdf.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="plclient.rc"> + <Filter>Resource Files</Filter> + </ResourceCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/powerlimit/plclient/powerlimitclient_drvinterface.h b/powerlimit/plclient/powerlimitclient_drvinterface.h new file mode 100644 index 00000000..d4c71bda --- /dev/null +++ b/powerlimit/plclient/powerlimitclient_drvinterface.h @@ -0,0 +1,58 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + powerlimitclient_drvinterface.h + +Abstract: + + This module contains the interfaces used to communicate with the simulate + power limit client driver stack. + +--*/ + +//--------------------------------------------------------------------- Pragmas + +#pragma once + +//--------------------------------------------------------------------- Defines + +// +// IOCTLs to control the client driver +// + +#define POWERLIMITCLIENT_IOCTL(_index_) \ + CTL_CODE(FILE_DEVICE_UNKNOWN, _index_, METHOD_BUFFERED, FILE_WRITE_DATA) + +// +// IOCTL_POWERLIMIT_CLIENT_QUERY_LIMIT_COUNT +// - Output: ULONG, number of supported power limit parameters. +// + +#define IOCTL_POWERLIMIT_CLIENT_QUERY_LIMIT_COUNT POWERLIMITCLIENT_IOCTL(0x800) + +// +// IOCTL_POWERLIMIT_CLIENT_QUERY_ATTRIBUTES +// - Output: POWER_LIMIT_ATTRIBUTES[], attributes of supported power limit parameters. +// + +#define IOCTL_POWERLIMIT_CLIENT_QUERY_ATTRIBUTES POWERLIMITCLIENT_IOCTL(0x801) + +// +// IOCTL_POWERLIMIT_CLIENT_QUERY_LIMITS +// - Output: POWER_LIMIT_VALUE[], values of supported power limit parameters. +// + +#define IOCTL_POWERLIMIT_CLIENT_QUERY_LIMITS POWERLIMITCLIENT_IOCTL(0x802) + +// +// Each domain supports PowerLimitContinuous/Burst/BurstTimeParameter. +// + +#define PLCLIENT_DEFAULT_LIMIT_COUNT_PER_DOMAIN 3UL +#define PLCLIENT_DEFAULT_DOMAIN_COUNT 2UL +#define PLCLIENT_DEFAULT_LIMIT_COUNT PLCLIENT_DEFAULT_LIMIT_COUNT_PER_DOMAIN * PLCLIENT_DEFAULT_DOMAIN_COUNT +#define PLCLIENT_DEFAULT_MAX_VALUE 50000UL +#define PLCLIENT_DEFAULT_MIN_VALUE 1000UL diff --git a/powerlimit/plclient/wdf.c b/powerlimit/plclient/wdf.c new file mode 100644 index 00000000..f5d0eb9b --- /dev/null +++ b/powerlimit/plclient/wdf.c @@ -0,0 +1,477 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + wdf.c + +Abstract: + + The module implements WDF boilerplate for the simulate power limit client. + +--*/ + +//-------------------------------------------------------------------- Includes + +#include "plclient.h" + +//--------------------------------------------------------------------- Globals + +WDFWAITLOCK GlobalMutex; + +//------------------------------------------------------------------ Prototypes + +DRIVER_INITIALIZE DriverEntry; +EVT_WDF_DRIVER_DEVICE_ADD EvtDriverDeviceAdd; +EVT_WDF_DRIVER_UNLOAD EvtDriverUnload; +EVT_WDF_OBJECT_CONTEXT_DESTROY EvtDeviceDestroy; +EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL EvtIoDeviceControl; + +//--------------------------------------------------------------------- Pragmas + +#pragma alloc_text(INIT, DriverEntry) +#pragma alloc_text(PAGE, EvtDriverDeviceAdd) +#pragma alloc_text(PAGE, EvtDriverUnload) +#pragma alloc_text(PAGE, EvtIoDeviceControl) +#pragma alloc_text(PAGE, EvtDeviceDestroy) + +//------------------------------------------------------------------- Functions + +_Use_decl_annotations_ +NTSTATUS +DriverEntry ( + _In_ PDRIVER_OBJECT DriverObject, + _In_ PUNICODE_STRING RegistryPath + ) + +/*++ + +Routine Description: + + DriverEntry initializes the driver and is the first routine called by the + system after the driver is loaded. DriverEntry configures and creates a WDF + driver object. + +Parameters Description: + + DriverObject - Supplies a pointer to the driver object. + + RegistryPath - Supplies a pointer to a unicode string representing the path + to the driver-specific key in the registry. + +Return Value: + + NTSTATUS. + +--*/ + +{ + + WDF_DRIVER_CONFIG DriverConfig; + NTSTATUS Status; + + UNREFERENCED_PARAMETER(RegistryPath); + + // + // Initiialize the DriverConfig data that controls the attributes that are + // global to this driver. + // + + DebugEnter(); + WDF_DRIVER_CONFIG_INIT(&DriverConfig, EvtDriverDeviceAdd); + DriverConfig.EvtDriverUnload = EvtDriverUnload; + + // + // Create the driver object + // + + Status = WdfDriverCreate(DriverObject, + RegistryPath, + WDF_NO_OBJECT_ATTRIBUTES, + &DriverConfig, + WDF_NO_HANDLE); + + if (!NT_SUCCESS(Status)) { + DebugPrint(PLCLIENT_PRINT_ERROR, + "WdfDriverCreate() Failed. Status 0x%x\n", + Status); + + goto DriverEntryEnd; + } + + // + // Initialize global mutex. + // + + Status = WdfWaitLockCreate(WDF_NO_OBJECT_ATTRIBUTES, &GlobalMutex); + if (!NT_SUCCESS(Status)) { + DebugPrint(PLCLIENT_PRINT_ERROR, + "WdfWaitLockCreate() Failed! 0x%x\n", + Status); + + goto DriverEntryEnd; + } + +DriverEntryEnd: + DebugExitStatus(Status); + return Status; +} + +_Use_decl_annotations_ +NTSTATUS +EvtDriverDeviceAdd ( + WDFDRIVER Driver, + PWDFDEVICE_INIT DeviceInit + ) + +/*++ + +Routine Description: + + This routine is called by the framework in response to AddDevice call from + the PnP manager. A WDF device object is created and initialized to represent + a new instance of the power limit client device. + +Arguments: + + Driver - Supplies a handle to the WDF Driver object. + + DeviceInit - Supplies a pointer to a framework-allocated WDFDEVICE_INIT structure. + +Return Value: + + NTSTATUS + +--*/ + +{ + + PFDO_DATA DevExt; + WDF_OBJECT_ATTRIBUTES DeviceAttributes; + WDFDEVICE DeviceHandle; + POWER_LIMIT_INTERFACE PowerLimitInterface; + WDFQUEUE Queue; + WDF_IO_QUEUE_CONFIG QueueConfig; + WDF_QUERY_INTERFACE_CONFIG QueryInterfaceConfig; + NTSTATUS Status; + + UNREFERENCED_PARAMETER(Driver); + + PAGED_CODE(); + + DevExt = NULL; + + DebugEnter(); + + // + // Initialize attributes and a context area for the device object. + // + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&DeviceAttributes, FDO_DATA); + DeviceAttributes.EvtDestroyCallback = &EvtDeviceDestroy; + + // + // Create a framework device object. This call will in turn create + // a WDM device object, attach to the lower stack, and set the + // appropriate flags and attributes. + // + + Status = WdfDeviceCreate(&DeviceInit, &DeviceAttributes, &DeviceHandle); + if (!NT_SUCCESS(Status)) { + DebugPrint(PLCLIENT_PRINT_ERROR, + "WdfDeviceCreate() Failed. 0x%x\n", + Status); + + goto DriverDeviceAddEnd; + } + + // + // Configure a default queue for IO requests. This queue processes requests + // to read the simulated state. + // + // N.B. Those IOCTLs supplies another approach to validate device driver + // interface, which are not needed by production code. + // + + WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&QueueConfig, + WdfIoQueueDispatchSequential); + + QueueConfig.EvtIoDeviceControl = EvtIoDeviceControl; + Status = WdfIoQueueCreate(DeviceHandle, + &QueueConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &Queue); + + if (!NT_SUCCESS(Status)) { + DebugPrint(PLCLIENT_PRINT_ERROR, + "WdfIoQueueCreate() Failed. 0x%x\n", + Status); + + goto DriverDeviceAddEnd; + } + + // + // Initialize the device extension. + // + + DevExt = GetDeviceExtension(DeviceHandle); + Status = InitPowerLimitValues(DevExt); + if (!NT_SUCCESS(Status)) { + DebugPrint(PLCLIENT_PRINT_ERROR, + "InitPowerLimitValues() Failed. 0x%x\n", + Status); + + goto DriverDeviceAddEnd; + } + + // + // Create a device interface for this device to advertise the simulated + // power limit client IO interface. + // + + Status = WdfDeviceCreateDeviceInterface( + DeviceHandle, + &GUID_DEVINTERFACE_POWER_LIMIT, + NULL); + + if (!NT_SUCCESS(Status)) { + goto DriverDeviceAddEnd; + } + + // + // Create a driver interface for this device to advertise the power limit + // interface. + // + + RtlZeroMemory(&PowerLimitInterface, sizeof(PowerLimitInterface)); + PowerLimitInterface.Version = 1; + PowerLimitInterface.Size = sizeof(PowerLimitInterface); + PowerLimitInterface.Context = DeviceHandle; + PowerLimitInterface.InterfaceReference = WdfDeviceInterfaceReferenceNoOp; + PowerLimitInterface.InterfaceDereference = WdfDeviceInterfaceDereferenceNoOp; + PowerLimitInterface.DomainCount = PLCLIENT_DEFAULT_DOMAIN_COUNT; + PowerLimitInterface.QueryAttributes = PLCQueryAttributes; + PowerLimitInterface.SetPowerLimit = PLCSetLimits; + PowerLimitInterface.QueryPowerLimit = PLCQueryLimitValues; + WDF_QUERY_INTERFACE_CONFIG_INIT(&QueryInterfaceConfig, + (PINTERFACE)&PowerLimitInterface, + &GUID_POWER_LIMIT_INTERFACE, + NULL); + + Status = WdfDeviceAddQueryInterface(DeviceHandle, &QueryInterfaceConfig); + if (!NT_SUCCESS(Status)) { + DebugPrint(PLCLIENT_PRINT_ERROR, + "WdfDeviceAddQueryInterface() Failed. 0x%x\n", + Status); + + goto DriverDeviceAddEnd; + } + +DriverDeviceAddEnd: + if (!NT_SUCCESS(Status)) { + CleanupPowerLimitValues(DevExt); + } + + DebugExitStatus(Status); + return Status; +} + +_Use_decl_annotations_ +VOID +EvtDeviceDestroy ( + WDFOBJECT Object + ) + +/*++ + +Routine Description: + + This routine destroys the device's data. + +Arguments: + + Object - Supplies the WDF reference to the device that is being removed. + +Return Value: + + None. + +--*/ + +{ + + PFDO_DATA DevExt; + + PAGED_CODE(); + + DebugEnter(); + DevExt = GetDeviceExtension(Object); + CleanupPowerLimitValues(DevExt); + DebugExit(); + return; +} + +_Use_decl_annotations_ +VOID +EvtIoDeviceControl ( + WDFQUEUE Queue, + WDFREQUEST Request, + size_t OutputBufferLength, + size_t InputBufferLength, + ULONG IoControlCode + ) + +/*++ + +Routine Description: + + Handles requests to read the simulated device state. + +Arguments: + + Queue - Supplies a handle to the framework queue object that is associated + with the I/O request. + + Request - Supplies a handle to a framework request object. This one + represents the IRP_MJ_DEVICE_CONTROL IRP received by the framework. + + OutputBufferLength - Supplies the length, in bytes, of the request's output + buffer, if an output buffer is available. + + InputBufferLength - Supplies the length, in bytes, of the request's input + buffer, if an input buffer is available. + + IoControlCode - Supplies the Driver-defined or system-defined I/O control + code (IOCTL) that is associated with the request. + +Return Value: + + VOID + +--*/ + +{ + + ULONG BytesReturned; + WDFDEVICE Device; + PFDO_DATA DevExt; + PVOID OutputBuffer; + NTSTATUS Status; + + UNREFERENCED_PARAMETER(InputBufferLength); + + PAGED_CODE(); + + Device = WdfIoQueueGetDevice(Queue); + DevExt = GetDeviceExtension(Device); + DebugPrint(PLCLIENT_PRINT_TRACE, + "EvtIoDeviceControl: 0x%08x\n", + IoControlCode); + + BytesReturned = 0; + OutputBuffer = NULL; + if (OutputBufferLength > 0) { + Status = WdfRequestRetrieveOutputBuffer(Request, + OutputBufferLength, + &OutputBuffer, + NULL); + + if (!NT_SUCCESS(Status)) { + goto DeviceIoControlEnd; + } + } + + Status = STATUS_NOT_SUPPORTED; + switch(IoControlCode) { + case IOCTL_POWERLIMIT_CLIENT_QUERY_LIMIT_COUNT: + if (OutputBufferLength == sizeof(ULONG)) { + AcquireGlobalMutex(); + *((PULONG)OutputBuffer) = DevExt->LimitCount; + BytesReturned = sizeof(ULONG); + ReleaseGlobalMutex(); + Status = STATUS_SUCCESS; + + } else { + Status = STATUS_BUFFER_OVERFLOW; + } + + break; + + case IOCTL_POWERLIMIT_CLIENT_QUERY_ATTRIBUTES: + if (OutputBufferLength == sizeof(POWER_LIMIT_ATTRIBUTES) * DevExt->LimitCount) { + AcquireGlobalMutex(); + RtlCopyMemory(OutputBuffer, DevExt->LimitAttributes, OutputBufferLength); + ReleaseGlobalMutex(); + BytesReturned = (ULONG)OutputBufferLength; + Status = STATUS_SUCCESS; + + } else { + Status = STATUS_BUFFER_OVERFLOW; + } + + break; + + case IOCTL_POWERLIMIT_CLIENT_QUERY_LIMITS: + if (OutputBufferLength == sizeof(POWER_LIMIT_VALUE) * DevExt->LimitCount) { + AcquireGlobalMutex(); + RtlCopyMemory(OutputBuffer, DevExt->LimitValues, OutputBufferLength); + ReleaseGlobalMutex(); + BytesReturned = (ULONG)OutputBufferLength; + Status = STATUS_SUCCESS; + + } else { + Status = STATUS_BUFFER_OVERFLOW; + } + + break; + + default: + break; + } + +DeviceIoControlEnd: + WdfRequestCompleteWithInformation(Request, Status, BytesReturned); + DebugExitStatus(Status); + return; +} + +_Use_decl_annotations_ +VOID +EvtDriverUnload ( + WDFDRIVER Driver + ) + +/*++ + +Routine Description: + + EvtDriverUnload is called when the driver is being unloaded to clean up + driver state. + +Arguments: + + Driver - Supplies a handle to the WDF Driver object. + +Return Value: + + None + +--*/ + +{ + + UNREFERENCED_PARAMETER(Driver); + + PAGED_CODE(); + + DebugEnter(); + + // + // N.B. Does nothing since we don't have anything to clean up, just print + // some debug info. + // + + DebugExit(); + return; +} |
