summaryrefslogtreecommitdiff
path: root/powerlimit/plpolicy
diff options
context:
space:
mode:
Diffstat (limited to 'powerlimit/plpolicy')
-rw-r--r--powerlimit/plpolicy/README.md38
-rw-r--r--powerlimit/plpolicy/plpolicy.c611
-rw-r--r--powerlimit/plpolicy/plpolicy.h128
-rw-r--r--powerlimit/plpolicy/plpolicy.inf82
-rw-r--r--powerlimit/plpolicy/plpolicy.rc10
-rw-r--r--powerlimit/plpolicy/plpolicy.sln35
-rw-r--r--powerlimit/plpolicy/plpolicy.vcxproj123
-rw-r--r--powerlimit/plpolicy/plpolicy.vcxproj.filters47
-rw-r--r--powerlimit/plpolicy/powerlimitpolicy_drvinterface.h85
-rw-r--r--powerlimit/plpolicy/wdf.c620
10 files changed, 1779 insertions, 0 deletions
diff --git a/powerlimit/plpolicy/README.md b/powerlimit/plpolicy/README.md
new file mode 100644
index 00000000..f23c22e3
--- /dev/null
+++ b/powerlimit/plpolicy/README.md
@@ -0,0 +1,38 @@
+---
+page_type: sample
+description: "Demonstrates a simulated power policy device."
+languages:
+- cpp
+products:
+- windows
+- windows-wdk
+---
+
+# plpolicy - Simulated Power Limit Policy Driver
+
+This sample is a driver for a simulated power limit policy device.
+
+## Universal Windows Driver Compliant
+
+The plpolicy sample provides the source code for a power limit controller that supplies power limit management to the operating system.
+
+This driver supplies IOCTLs to receive commands from other modules and plumb cooresponding information to the hardware through OS kernel
+space APIs.
+
+IOCTL_POWERLIMIT_POLICY_REGISTER: Other module supplies the BIOS name of the target device to control the power limit.
+
+IOCTL_POWERLIMIT_POLICY_QUERY_ATTRIBUTES: Query the target device for supported power limits and attributes.
+
+IOCTL_POWERLIMIT_POLICY_QUERY_VALUES: Query the target device for active power limit values.
+
+IOCTL_POWERLIMIT_POLICY_SET_VALUES: Set power limit values to the target device.
+
+For a production driver, those IOCTLs are not needed. Instead, the policy driver should:
+1. During the init phase, subscribes to GUID_DEVINTERFACE_POWER_LIMIT notifications. Then query client's BIOS name in the callback, and
+ compares it with the target client device. Then create power limit request through PoCreatePowerLimitRequest, query attributes through
+ PoQueryPowerLimitAttributes.
+
+2. At runtime, the policy driver should collect input signals and calcualte power limit target(s), then send targets to the client through
+ PoSetPowerLimitValue. If necessary, the policy driver can query the current power limit of client through PoQueryPowerLimitValue.
+
+3. If the power limit control is no longer needed, delete the power limit request through PoDeletePowerLimitRequest.
diff --git a/powerlimit/plpolicy/plpolicy.c b/powerlimit/plpolicy/plpolicy.c
new file mode 100644
index 00000000..e5db18cd
--- /dev/null
+++ b/powerlimit/plpolicy/plpolicy.c
@@ -0,0 +1,611 @@
+/*++
+
+Copyright (c) Microsoft Corporation
+
+Module Name:
+
+ plpolicy.c
+
+Abstract:
+
+ This module implements power limit related operations for the simulated power
+ limit policy driver.
+
+--*/
+
+//-------------------------------------------------------------------- Includes
+
+#include "plpolicy.h"
+
+//------------------------------------------------------------------ Prototypes
+
+NTSTATUS
+GetDeviceObjectFromInterfaceName (
+ _In_ PUNICODE_STRING Name,
+ _Outptr_ PFILE_OBJECT *File,
+ _Outptr_ PDEVICE_OBJECT *Device
+ );
+
+PDEVICE_REGISTRATION
+FindRegistrationByName (
+ _In_ PUNICODE_STRING TargetDeviceName,
+ _In_ PFDO_DATA DevExt
+ );
+
+PDEVICE_REGISTRATION
+FindRegistrationById (
+ _In_ PFDO_DATA DevExt,
+ _In_ ULONG RequestId
+ );
+
+//--------------------------------------------------------------------- Globals
+
+WDFWAITLOCK GlobalMutex;
+
+//--------------------------------------------------------------------- Pragmas
+
+#pragma alloc_text(PAGE, RegisterRequest)
+#pragma alloc_text(PAGE, UnregisterRequest)
+#pragma alloc_text(PAGE, QueryAttributes)
+#pragma alloc_text(PAGE, QueryLimitValues)
+#pragma alloc_text(PAGE, SetLimitValues)
+#pragma alloc_text(PAGE, GetDeviceObjectFromInterfaceName)
+#pragma alloc_text(PAGE, FindRegistrationByName)
+#pragma alloc_text(PAGE, FindRegistrationById)
+
+//------------------------------------------------------------------- Functions
+
+_Use_decl_annotations_
+NTSTATUS
+RegisterRequest (
+ PFDO_DATA DevExt,
+ PUNICODE_STRING TargetDeviceName,
+ PDEVICE_OBJECT PolicyDeviceObject,
+ PULONG RequestId
+ )
+
+/*++
+
+Routine Description:
+
+ This routine registers a power limit request for the specified device.
+
+Arguments:
+
+ DevExt - Supplies a pointer to the device extension.
+
+ TargetDeviceName - Supplies the name of the target device.
+
+ PolicyDeviceObject - Supplies a pointer to the policy driver's device object.
+
+ RequestId - Supplies a pointer to the registered request.
+
+Return Value:
+
+ NTSTATUS.
+
+--*/
+
+{
+
+ PFILE_OBJECT FileObject;
+ COUNTED_REASON_CONTEXT ReasContext;
+ PDEVICE_REGISTRATION Registration;
+ ULONG SizeNeeded;
+ NTSTATUS Status;
+ PDEVICE_OBJECT TargetDeviceObject;
+
+ PAGED_CODE();
+
+ FileObject = NULL;
+ TargetDeviceObject = NULL;
+ Registration = NULL;
+ AcquireGlobalMutex();
+ if (FindRegistrationByName(TargetDeviceName, DevExt) != NULL) {
+ Status = STATUS_SUCCESS;
+ goto RegisterEnd;
+ }
+
+ Status = GetDeviceObjectFromInterfaceName(TargetDeviceName,
+ &FileObject,
+ &TargetDeviceObject);
+
+ if (!NT_SUCCESS(Status)) {
+ goto RegisterEnd;
+ }
+
+ SizeNeeded = sizeof(DEVICE_REGISTRATION) + TargetDeviceName->MaximumLength;
+ Registration = ExAllocatePool2(POOL_FLAG_PAGED, SizeNeeded, PLPOLICY_TAG);
+ if (Registration == NULL) {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto RegisterEnd;
+ }
+
+ RtlZeroMemory(Registration, SizeNeeded);
+ Registration->TargetDeviceName.Length = TargetDeviceName->Length;
+ Registration->TargetDeviceName.MaximumLength = TargetDeviceName->MaximumLength;
+ Registration->TargetDeviceName.Buffer = OffsetToPtr(Registration,
+ sizeof(DEVICE_REGISTRATION));
+
+ RtlCopyMemory(Registration->TargetDeviceName.Buffer,
+ TargetDeviceName->Buffer,
+ TargetDeviceName->MaximumLength);
+
+ ReasContext.Version = DIAGNOSTIC_REASON_VERSION;
+ ReasContext.Flags = DIAGNOSTIC_REASON_SIMPLE_STRING;
+ RtlInitUnicodeString(&ReasContext.SimpleString, L"Simulated Power Limit Policy Device");
+ Status = PoCreatePowerLimitRequest(&Registration->PowerLimitRequest,
+ TargetDeviceObject,
+ PolicyDeviceObject,
+ &ReasContext);
+
+ if (!NT_SUCCESS(Status)) {
+ goto RegisterEnd;
+ }
+
+ Registration->Initialized = TRUE;
+ Registration->RequestId = DevExt->RequestCount;
+ *RequestId = DevExt->RequestCount;
+ InsertTailList(&DevExt->RequestHeader, &Registration->Link);
+ DevExt->RequestCount += 1;
+ Registration = NULL;
+ Status = STATUS_SUCCESS;
+
+RegisterEnd:
+ ReleaseGlobalMutex();
+ if (FileObject != NULL) {
+ ObDereferenceObject(FileObject);
+ }
+
+ if (TargetDeviceObject != NULL) {
+ ObDereferenceObject(TargetDeviceObject);
+ }
+
+ if (Registration != NULL) {
+ ExFreePoolWithTag(Registration, PLPOLICY_TAG);
+ }
+
+ return Status;
+}
+
+_Use_decl_annotations_
+NTSTATUS
+UnregisterRequest (
+ PFDO_DATA DevExt,
+ ULONG RequestId
+ )
+
+/*++
+
+Routine Description:
+
+ This routine unregisters a power limit request for the specified device.
+
+Arguments:
+
+ DevExt - Supplies a pointer to the device extension.
+
+ RequestId - Supplies the Id of the request.
+
+Return Value:
+
+ NTSTATUS.
+
+--*/
+
+{
+
+ PDEVICE_REGISTRATION Registration;
+ NTSTATUS Status;
+
+ PAGED_CODE();
+
+ AcquireGlobalMutex();
+ Registration = FindRegistrationById(DevExt, RequestId);
+ if (Registration == NULL) {
+ Status = STATUS_OBJECT_NAME_NOT_FOUND;
+ goto UnregisterEnd;
+ }
+
+ RemoveEntryList(&Registration->Link);
+ PoDeletePowerLimitRequest(Registration->PowerLimitRequest);
+ ExFreePoolWithTag(Registration, PLPOLICY_TAG);
+ Status = STATUS_SUCCESS;
+
+UnregisterEnd:
+ ReleaseGlobalMutex();
+ return Status;
+}
+
+_Use_decl_annotations_
+NTSTATUS
+QueryAttributes (
+ PPOWER_LIMIT_ATTRIBUTES Buffer,
+ PFDO_DATA DevExt,
+ ULONG RequestId,
+ ULONG BufferCount
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns supported power limit parameter's attributes.
+
+Arguments:
+
+ Buffer - Supplies a pointer to save attributes.
+
+ DevExt - Supplies a pointer to the device extension.
+
+ RequestId - Supplies the Id of the request.
+
+ BufferCount - Supplies the count of buffer.
+
+Return Value:
+
+ NTSTATUS.
+
+--*/
+
+{
+
+ ULONG AttributeCount;
+ PDEVICE_REGISTRATION Registration;
+ NTSTATUS Status;
+
+ PAGED_CODE();
+
+ AcquireGlobalMutex();
+ Registration = FindRegistrationById(DevExt, RequestId);
+ if (Registration == NULL) {
+ Status = STATUS_OBJECT_NAME_NOT_FOUND;
+ goto QueryAttributesEnd;
+ }
+
+ Status = PoQueryPowerLimitAttributes(Registration->PowerLimitRequest,
+ BufferCount,
+ Buffer,
+ &AttributeCount);
+
+QueryAttributesEnd:
+ ReleaseGlobalMutex();
+ return Status;
+}
+
+_Use_decl_annotations_
+NTSTATUS
+QueryLimitValues (
+ PPOWER_LIMIT_VALUE Buffer,
+ PFDO_DATA DevExt,
+ ULONG RequestId,
+ ULONG BufferCount
+ )
+
+/*++
+
+Routine Description:
+
+ This routine checks values of power limits.
+
+Arguments:
+
+ Buffer - Supplies a pointer to save values.
+
+ DevExt - Supplies a pointer to the device extension.
+
+ RequestId - Supplies the Id of the request.
+
+ BufferCount - Supplies the count of buffer.
+
+Return Value:
+
+ NTSTATUS.
+
+--*/
+
+{
+
+ PDEVICE_REGISTRATION Registration;
+ NTSTATUS Status;
+
+ PAGED_CODE();
+
+ AcquireGlobalMutex();
+ Registration = FindRegistrationById(DevExt, RequestId);
+ if (Registration == NULL) {
+ Status = STATUS_OBJECT_NAME_NOT_FOUND;
+ goto QueryLimitValuesEnd;
+ }
+
+ Status = PoQueryPowerLimitValue(Registration->PowerLimitRequest,
+ BufferCount,
+ Buffer);
+
+QueryLimitValuesEnd:
+ ReleaseGlobalMutex();
+ return Status;
+}
+
+_Use_decl_annotations_
+NTSTATUS
+SetLimitValues (
+ PFDO_DATA DevExt,
+ ULONG RequestId,
+ ULONG BufferCount,
+ PPOWER_LIMIT_VALUE Buffer
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets values of power limits.
+
+Arguments:
+
+ DevExt - Supplies a pointer to the device extension.
+
+ RequestId - Supplies the Id of the request.
+
+ BufferCount - Supplies the count of buffer.
+
+ Buffer - Supplies a pointer to proposed control values.
+
+Return Value:
+
+ NTSTATUS.
+
+--*/
+
+{
+
+ COUNTED_REASON_CONTEXT ReasContext;
+ PDEVICE_REGISTRATION Registration;
+ NTSTATUS Status;
+
+ PAGED_CODE();
+
+ AcquireGlobalMutex();
+ Registration = FindRegistrationById(DevExt, RequestId);
+ if (Registration == NULL) {
+ Status = STATUS_OBJECT_NAME_NOT_FOUND;
+ goto QueryLimitValuesEnd;
+ }
+
+ ReasContext.Version = DIAGNOSTIC_REASON_VERSION;
+ ReasContext.Flags = DIAGNOSTIC_REASON_SIMPLE_STRING;
+ RtlInitUnicodeString(&ReasContext.SimpleString, L"Sim PL Policy");
+ Status = PoSetPowerLimitValue(Registration->PowerLimitRequest,
+ &ReasContext,
+ BufferCount,
+ Buffer);
+
+QueryLimitValuesEnd:
+ ReleaseGlobalMutex();
+ return Status;
+}
+
+NTSTATUS
+GetDeviceObjectFromInterfaceName (
+ _In_ PUNICODE_STRING Name,
+ _Outptr_ PFILE_OBJECT *File,
+ _Outptr_ PDEVICE_OBJECT *Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine retrieves the device object for the named interface.
+
+Arguments:
+
+ Name - Supplies a pointer to the name of the device interface.
+
+ File - Supplies a pointer to a location to receive the file object.
+
+ Device - Supplies a pointer to a location to receive the device object.
+
+Return Value:
+
+ NTSTATUS.
+
+--*/
+
+{
+
+ OBJECT_ATTRIBUTES Attributes;
+ PDEVICE_OBJECT DeviceObject;
+ PFILE_OBJECT FileObject;
+ HANDLE Handle;
+ IO_STATUS_BLOCK IoStatus;
+ NTSTATUS Status;
+
+ PAGED_CODE();
+
+ DeviceObject = NULL;
+ FileObject = NULL;
+ Handle = NULL;
+ InitializeObjectAttributes(&Attributes,
+ Name,
+ OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
+ NULL,
+ NULL);
+
+ //
+ // Open a handle to the device.
+ //
+
+ Status = ZwCreateFile(&Handle,
+ FILE_ALL_ACCESS,
+ &Attributes,
+ &IoStatus,
+ NULL,
+ 0,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_OPEN,
+ 0,
+ NULL,
+ 0);
+
+ if (!NT_SUCCESS(Status)) {
+ Handle = NULL;
+ goto GetInterfaceDeviceObjectEnd;
+ }
+
+ //
+ // Retrieve the file object associated with the device handle.
+ //
+
+ Status = ObReferenceObjectByHandle(Handle,
+ 0,
+ *IoFileObjectType,
+ KernelMode,
+ &FileObject,
+ NULL);
+
+ if (!NT_SUCCESS(Status)) {
+ FileObject = NULL;
+ goto GetInterfaceDeviceObjectEnd;
+ }
+
+ //
+ // Get the device object associated with the file object.
+ //
+ // N.B. The device object must be referenced before dereferencing the file
+ // object.
+ //
+
+ DeviceObject = IoGetRelatedDeviceObject(FileObject);
+ if (DeviceObject == NULL) {
+ Status = STATUS_UNSUCCESSFUL;
+ goto GetInterfaceDeviceObjectEnd;
+ }
+
+ ObReferenceObject(DeviceObject);
+ *File = FileObject;
+ *Device = DeviceObject;
+ FileObject = NULL;
+ Status = STATUS_SUCCESS;
+
+GetInterfaceDeviceObjectEnd:
+ if (FileObject != NULL) {
+ ObDereferenceObject(FileObject);
+ }
+
+ if (Handle != NULL) {
+ ZwClose(Handle);
+ }
+
+ return Status;
+}
+
+_Use_decl_annotations_
+PDEVICE_REGISTRATION
+FindRegistrationByName (
+ PUNICODE_STRING TargetDeviceName,
+ PFDO_DATA DevExt
+ )
+
+/*++
+
+Routine Description:
+
+ This routine searches for an existing registration matching the given
+ device name.
+
+Arguments:
+
+ TargetDeviceName - Supplies the PDO name of the device.
+
+ DevExt - Supplies a pointer to the device extension.
+
+Return Value:
+
+ A pointer to the device registration, if it is found. Otherwise, NULL.
+
+--*/
+
+{
+
+ LONG Comparison;
+ PLIST_ENTRY Link;
+ PDEVICE_REGISTRATION Registration;
+
+ Registration = NULL;
+ if (DevExt->RequestCount == 0) {
+ goto FindRegistrationByNameEnd;
+ }
+
+ for (Link = DevExt->RequestHeader.Flink;
+ Link != &DevExt->RequestHeader;
+ Link = Link->Flink) {
+
+ Registration = CONTAINING_RECORD(Link, DEVICE_REGISTRATION, Link);
+ Comparison = RtlCompareUnicodeString(TargetDeviceName,
+ &Registration->TargetDeviceName,
+ FALSE);
+
+ if (Comparison == 0) {
+ break;
+ }
+
+ Registration = NULL;
+ }
+
+FindRegistrationByNameEnd:
+ return Registration;
+}
+
+_Use_decl_annotations_
+PDEVICE_REGISTRATION
+FindRegistrationById (
+ PFDO_DATA DevExt,
+ ULONG RequestId
+ )
+
+/*++
+
+Routine Description:
+
+ This routine searches for an existing registration matching the given
+ device name.
+
+Arguments:
+
+ TargetDeviceName - Supplies the PDO name of the device.
+
+ RequestId - Supplies the ID of the power limit request.
+
+Return Value:
+
+ A pointer to the device registration, if it is found. Otherwise, NULL.
+
+--*/
+
+{
+
+ PLIST_ENTRY Link;
+ PDEVICE_REGISTRATION Registration;
+
+ Registration = NULL;
+ if (DevExt->RequestCount == 0) {
+ goto FindRegistrationByIdEnd;
+ }
+
+ for (Link = DevExt->RequestHeader.Flink;
+ Link != &DevExt->RequestHeader;
+ Link = Link->Flink) {
+
+ Registration = CONTAINING_RECORD(Link, DEVICE_REGISTRATION, Link);
+ if (Registration->RequestId == RequestId) {
+ break;
+ }
+
+ Registration = NULL;
+ }
+
+FindRegistrationByIdEnd:
+ return Registration;
+} \ No newline at end of file
diff --git a/powerlimit/plpolicy/plpolicy.h b/powerlimit/plpolicy/plpolicy.h
new file mode 100644
index 00000000..ae767b63
--- /dev/null
+++ b/powerlimit/plpolicy/plpolicy.h
@@ -0,0 +1,128 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+Module Name:
+
+ plpolicy.h
+
+Abstract:
+
+ This is the header file for the simulated power limit policy 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 "powerlimitpolicy_drvinterface.h"
+
+//----------------------------------------------------------------------- Types
+
+typedef struct _DEVICE_REGISTRATION {
+ LIST_ENTRY Link;
+ BOOLEAN Initialized;
+ ULONG RequestId;
+ PVOID PowerLimitRequest;
+ UNICODE_STRING TargetDeviceName;
+} DEVICE_REGISTRATION, *PDEVICE_REGISTRATION;
+
+typedef struct _FDO_DATA {
+ ULONG RequestCount;
+ LIST_ENTRY RequestHeader;
+} FDO_DATA, *PFDO_DATA;
+
+WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(FDO_DATA, GetDeviceExtension);
+
+//----------------------------------------------------------------------- Debug
+
+#define DebugPrint(l, m, ...) DbgPrintEx(DPFLTR_POWER_ID, l, "[plpolicy]: "m, __VA_ARGS__)
+#define DebugEnter() DebugPrint(PLPOLICY_PRINT_TRACE, "Entering " __FUNCTION__ "\n")
+#define DebugExit() DebugPrint(PLPOLICY_PRINT_TRACE, "Leaving " __FUNCTION__ "\n")
+#define DebugExitStatus(_status_) DebugPrint(PLPOLICY_PRINT_TRACE, "Leaving " __FUNCTION__ ": Status=0x%x\n", _status_)
+
+#define PLPOLICY_PRINT_ERROR DPFLTR_ERROR_LEVEL
+#define PLPOLICY_PRINT_TRACE DPFLTR_TRACE_LEVEL
+#define PLPOLICY_PRINT_INFO DPFLTR_INFO_LEVEL
+
+#define PLPOLICY_TAG 'PLPO'
+
+#define OffsetToPtr(Base, Offset) ((PVOID)((PUCHAR)(Base) + (Offset)))
+
+//--------------------------------------------------------------------- Globals
+
+extern WDFWAITLOCK GlobalMutex;
+
+//------------------------------------------------------------------ Prototypes
+
+FORCEINLINE
+VOID
+AcquireGlobalMutex (
+ VOID
+ )
+{
+
+ WdfWaitLockAcquire(GlobalMutex, 0);
+ return;
+}
+
+FORCEINLINE
+VOID
+ReleaseGlobalMutex (
+ VOID
+ )
+{
+
+ WdfWaitLockRelease(GlobalMutex);
+ return;
+}
+
+//
+// plpolicy.c
+//
+
+NTSTATUS
+RegisterRequest (
+ _Inout_ PFDO_DATA DevExt,
+ _In_ PUNICODE_STRING TargetDeviceName,
+ _In_ PDEVICE_OBJECT PolicyDeviceObject,
+ _Out_ PULONG RequestId
+ );
+
+NTSTATUS
+UnregisterRequest (
+ _Inout_ PFDO_DATA DevExt,
+ _In_ ULONG RequestId
+ );
+
+NTSTATUS
+QueryAttributes (
+ _Out_ PPOWER_LIMIT_ATTRIBUTES Buffer,
+ _Inout_ PFDO_DATA DevExt,
+ _In_ ULONG RequestId,
+ _In_ ULONG BufferCount
+ );
+
+NTSTATUS
+QueryLimitValues (
+ _Out_ PPOWER_LIMIT_VALUE Buffer,
+ _Inout_ PFDO_DATA DevExt,
+ _In_ ULONG RequestId,
+ _In_ ULONG BufferCount
+ );
+
+NTSTATUS
+SetLimitValues (
+ _Inout_ PFDO_DATA DevExt,
+ _In_ ULONG RequestId,
+ _In_ ULONG BufferCount,
+ _In_ PPOWER_LIMIT_VALUE Buffer
+ );
diff --git a/powerlimit/plpolicy/plpolicy.inf b/powerlimit/plpolicy/plpolicy.inf
new file mode 100644
index 00000000..ac5dc127
--- /dev/null
+++ b/powerlimit/plpolicy/plpolicy.inf
@@ -0,0 +1,82 @@
+;/*++
+;
+;Copyright (c) Microsoft Corporation All rights Reserved
+;
+;Module Name:
+;
+; plpolicy.inf
+;
+;Abstract:
+;
+; INF file for installing simulate power limit policy driver.
+;
+;--*/
+
+[Version]
+Signature="$WINDOWS NT$"
+Class=System
+ClassGuid={4D36E97D-E325-11CE-BFC1-08002BE10318}
+Provider=%ProviderString%
+DriverVer=08/29/2023,1.00.0000
+CatalogFile=plpolicy.cat
+PnpLockdown=1
+
+[DestinationDirs]
+DefaultDestDir = 12
+
+[SourceDisksNames]
+1 = %DiskId1%,,,""
+
+[SourceDisksFiles]
+plpolicy.sys = 1,,
+
+;*****************************************
+; Thermal Request Proxy Install Section
+;*****************************************
+
+[Manufacturer]
+%StdMfg%=Standard,NTamd64
+%StdMfg%=Standard,NTarm64
+
+[Standard.NTamd64]
+%plpolicy.DeviceDesc%=PLPolicy_Device,ACPI\PLPO0001
+%plpolicy.DeviceDesc%=PLPolicy_Device,root\PLPO0001
+
+[Standard.NTarm64]
+%plpolicy.DeviceDesc%=PLPolicy_Device,ACPI\PLPO0001
+%plpolicy.DeviceDesc%=PLPolicy_Device,root\PLPO0001
+
+[PLPolicy_Device.NT]
+CopyFiles=PLPolicy_Device.NT.Copy
+
+[PLPolicy_Device.NT.HW]
+AddReg=PLPolicy_Device.NT.AddReg
+
+[PLPolicy_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
+
+[PLPolicy_Device.NT.Copy]
+plpolicy.sys
+
+;-------------- Service installation
+
+[PLPolicy_Device.NT.Services]
+AddService = plpolicy,%SPSVCINST_ASSOCSERVICE%,PLPolicy_Service_Inst
+
+[PLPolicy_Service_Inst]
+DisplayName = %plpolicy.SVCDESC%
+ServiceType = 1 ; SERVICE_KERNEL_DRIVER
+StartType = 3 ; SERVICE_DEMAND_START
+ErrorControl = 1 ; SERVICE_ERROR_NORMAL
+ServiceBinary = %12%\plpolicy.sys
+LoadOrderGroup = System Reserved
+
+[Strings]
+SPSVCINST_ASSOCSERVICE= 0x00000002
+ProviderString = "TODO-Set-Provider"
+StdMfg = "(Standard system devices)"
+ClassName = "System devices"
+DiskId1 = "Simulate Power Limit Policy Installation Disk #1"
+plpolicy.DeviceDesc = "Simulate Power Limit Policy Device"
+plpolicy.SVCDESC = "Simulate Power Limit Policy Driver"
diff --git a/powerlimit/plpolicy/plpolicy.rc b/powerlimit/plpolicy/plpolicy.rc
new file mode 100644
index 00000000..0dbbb5ff
--- /dev/null
+++ b/powerlimit/plpolicy/plpolicy.rc
@@ -0,0 +1,10 @@
+#include <verrsrc.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
+#define VER_FILEDESCRIPTION_STR "Simulate Power Limit Policy Driver"
+#define VER_INTERNALNAME_STR "plpolicy.sys"
+#define VER_ORIGINALFILENAME_STR "plpolicy.sys"
+
+#include "common.ver"
diff --git a/powerlimit/plpolicy/plpolicy.sln b/powerlimit/plpolicy/plpolicy.sln
new file mode 100644
index 00000000..65827082
--- /dev/null
+++ b/powerlimit/plpolicy/plpolicy.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}") = "plpolicy", "plpolicy.vcxproj", "{F69B9212-A156-4EF1-8478-11228DE91DD3}"
+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
+ {F69B9212-A156-4EF1-8478-11228DE91DD3}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {F69B9212-A156-4EF1-8478-11228DE91DD3}.Debug|ARM64.Build.0 = Debug|ARM64
+ {F69B9212-A156-4EF1-8478-11228DE91DD3}.Debug|ARM64.Deploy.0 = Debug|ARM64
+ {F69B9212-A156-4EF1-8478-11228DE91DD3}.Debug|x64.ActiveCfg = Debug|x64
+ {F69B9212-A156-4EF1-8478-11228DE91DD3}.Debug|x64.Build.0 = Debug|x64
+ {F69B9212-A156-4EF1-8478-11228DE91DD3}.Debug|x64.Deploy.0 = Debug|x64
+ {F69B9212-A156-4EF1-8478-11228DE91DD3}.Release|ARM64.ActiveCfg = Release|ARM64
+ {F69B9212-A156-4EF1-8478-11228DE91DD3}.Release|ARM64.Build.0 = Release|ARM64
+ {F69B9212-A156-4EF1-8478-11228DE91DD3}.Release|ARM64.Deploy.0 = Release|ARM64
+ {F69B9212-A156-4EF1-8478-11228DE91DD3}.Release|x64.ActiveCfg = Release|x64
+ {F69B9212-A156-4EF1-8478-11228DE91DD3}.Release|x64.Build.0 = Release|x64
+ {F69B9212-A156-4EF1-8478-11228DE91DD3}.Release|x64.Deploy.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {ED084CB6-1513-41AF-9AF9-545395180D32}
+ EndGlobalSection
+EndGlobal
diff --git a/powerlimit/plpolicy/plpolicy.vcxproj b/powerlimit/plpolicy/plpolicy.vcxproj
new file mode 100644
index 00000000..bb0b948a
--- /dev/null
+++ b/powerlimit/plpolicy/plpolicy.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>{F69B9212-A156-4EF1-8478-11228DE91DD3}</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>plpolicy</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="plpolicy.inf" />
+ </ItemGroup>
+ <ItemGroup>
+ <FilesToPackage Include="$(TargetPath)" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="plpolicy.h" />
+ <ClInclude Include="powerlimitpolicy_drvinterface.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="plpolicy.c" />
+ <ClCompile Include="wdf.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="plpolicy.rc" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/powerlimit/plpolicy/plpolicy.vcxproj.filters b/powerlimit/plpolicy/plpolicy.vcxproj.filters
new file mode 100644
index 00000000..b2317860
--- /dev/null
+++ b/powerlimit/plpolicy/plpolicy.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="plpolicy.inf">
+ <Filter>Driver Files</Filter>
+ </Inf>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="plpolicy.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="powerlimitpolicy_drvinterface.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="plpolicy.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="wdf.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="plpolicy.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/powerlimit/plpolicy/powerlimitpolicy_drvinterface.h b/powerlimit/plpolicy/powerlimitpolicy_drvinterface.h
new file mode 100644
index 00000000..cd630ef6
--- /dev/null
+++ b/powerlimit/plpolicy/powerlimitpolicy_drvinterface.h
@@ -0,0 +1,85 @@
+/*++
+
+Copyright (c) Microsoft Corporation
+
+Module Name:
+
+ powerlimitpolicy_drvinterface.h
+
+Abstract:
+
+ This module contains the interfaces used to communicate with the simulate
+ power limit policy driver stack.
+
+--*/
+
+//--------------------------------------------------------------------- Pragmas
+
+#pragma once
+
+//--------------------------------------------------------------------- Defines
+
+//
+// Simulated power limit policy interface
+//
+
+// {dbdc0da1-563c-4e20-8408-d4e3c1069ea3}
+DEFINE_GUID(GUID_DEVINTERFACE_POWERLIMIT_POLICY,
+0xdbdc0da1, 0x563c, 0x4e20, 0x84, 0x08, 0xd4, 0xe3, 0xc1, 0x06, 0x9e, 0xa3);
+
+//
+// IOCTLs to control the policy driver
+//
+
+#define POWERLIMIT_POLICY_IOCTL(_index_) \
+ CTL_CODE(FILE_DEVICE_UNKNOWN, _index_, METHOD_BUFFERED, FILE_WRITE_DATA)
+
+//
+// IOCTL_POWERLIMIT_POLICY_REGISTER
+// - Input: WCHAR[], contains interface name of the target device
+// - Output: ULONG, Id of the created power limit
+//
+
+#define IOCTL_POWERLIMIT_POLICY_REGISTER POWERLIMIT_POLICY_IOCTL(0x800)
+
+//
+// IOCTL_POWERLIMIT_POLICY_UNREGISTER
+// - Input: ULONG, Id of the power limit to unregister
+//
+
+#define IOCTL_POWERLIMIT_POLICY_UNREGISTER POWERLIMIT_POLICY_IOCTL(0x801)
+
+//
+// IOCTL_POWERLIMIT_POLICY_QUERY_ATTRIBUTES
+// - Input: POWERLIMIT_POLICY_ATTRIBUTES
+// - Output: POWERLIMIT_POLICY_ATTRIBUTES
+//
+
+#define IOCTL_POWERLIMIT_POLICY_QUERY_ATTRIBUTES POWERLIMIT_POLICY_IOCTL(0x802)
+
+//
+// IOCTL_POWERLIMIT_POLICY_QUERY_VALUES
+// - Input: POWERLIMIT_POLICY_VALUES
+// - Output: POWERLIMIT_POLICY_VALUES
+//
+
+#define IOCTL_POWERLIMIT_POLICY_QUERY_VALUES POWERLIMIT_POLICY_IOCTL(0x803)
+
+//
+// IOCTL_POWERLIMIT_POLICY_SET_VALUES
+// - Input: POWERLIMIT_POLICY_VALUES, values to be updated for target power limit request
+//
+
+#define IOCTL_POWERLIMIT_POLICY_SET_VALUES POWERLIMIT_POLICY_IOCTL(0x804)
+
+typedef struct _POWERLIMIT_POLICY_ATTRIBUTES {
+ ULONG RequestId;
+ ULONG BufferCount;
+ POWER_LIMIT_ATTRIBUTES Buffer[ANYSIZE_ARRAY];
+} POWERLIMIT_POLICY_ATTRIBUTES, *PPOWERLIMIT_POLICY_ATTRIBUTES;
+
+typedef struct _POWERLIMIT_POLICY_VALUES {
+ ULONG RequestId;
+ ULONG BufferCount;
+ POWER_LIMIT_VALUE Buffer[ANYSIZE_ARRAY];
+} POWERLIMIT_POLICY_VALUES, *PPOWERLIMIT_POLICY_VALUES;
diff --git a/powerlimit/plpolicy/wdf.c b/powerlimit/plpolicy/wdf.c
new file mode 100644
index 00000000..14760ac7
--- /dev/null
+++ b/powerlimit/plpolicy/wdf.c
@@ -0,0 +1,620 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+Module Name:
+
+ wdf.c
+
+Abstract:
+
+ The module implements WDF boilerplate for the simulate power limit policy.
+
+--*/
+
+//-------------------------------------------------------------------- Includes
+
+#include "plpolicy.h"
+
+//------------------------------------------------------------------ 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;
+
+NTSTATUS
+GetDeviceName (
+ _Out_ PUNICODE_STRING DeviceName,
+ _In_reads_bytes_(BufferLength) PWCHAR Buffer,
+ _In_ SIZE_T BufferLength
+ );
+
+//--------------------------------------------------------------------- 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)
+#pragma alloc_text(PAGE, GetDeviceName)
+
+//------------------------------------------------------------------- Functions
+
+_Use_decl_annotations_
+NTSTATUS
+DriverEntry (
+ PDRIVER_OBJECT DriverObject,
+ 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 a framework driver object to represent this driver.
+ //
+
+ Status = WdfDriverCreate(DriverObject,
+ RegistryPath,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &DriverConfig,
+ WDF_NO_HANDLE);
+
+ if (!NT_SUCCESS(Status)) {
+ DebugPrint(PLPOLICY_PRINT_ERROR,
+ "WdfDriverCreate() Failed! 0x%x\n",
+ Status);
+
+ goto DriverEntryEnd;
+ }
+
+ //
+ // Initialize global mutex.
+ //
+
+ Status = WdfWaitLockCreate(WDF_NO_OBJECT_ATTRIBUTES, &GlobalMutex);
+ if (!NT_SUCCESS(Status)) {
+ DebugPrint(PLPOLICY_PRINT_ERROR,
+ "WdfSpinLockCreate() Failed! 0x%x\n",
+ Status);
+
+ goto DriverEntryEnd;
+ }
+
+ Status = STATUS_SUCCESS;
+
+DriverEntryEnd:
+ DebugExitStatus(Status);
+ return Status;
+}
+
+_Use_decl_annotations_
+NTSTATUS
+EvtDriverDeviceAdd (
+ WDFDRIVER Driver,
+ PWDFDEVICE_INIT DeviceInit
+ )
+
+/*++
+
+Routine Description:
+
+ EvtDriverDeviceAdd is called by the framework in response to AddDevice
+ call from the PnP manager. A WDF device object is created and initailized to
+ represent the simulation control interface.
+
+Arguments:
+
+ Driver - Supplies a handle to a framework driver object created in
+ DriverEntry
+
+ DeviceInit - Supplies a pointer to a framework-allocated WDFDEVICE_INIT
+ structure.
+
+Return Value:
+
+ NTSTATUS
+
+--*/
+
+{
+
+ PFDO_DATA DevExt;
+ WDF_OBJECT_ATTRIBUTES DeviceAttributes;
+ WDFDEVICE DeviceHandle;
+ WDF_IO_QUEUE_CONFIG IoQueueConfig;
+ WDFQUEUE Queue;
+ NTSTATUS Status;
+
+ UNREFERENCED_PARAMETER(Driver);
+
+ PAGED_CODE();
+
+ 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(PLPOLICY_PRINT_ERROR,
+ "WdfDeviceCreate() Failed! 0x%x\n",
+ Status);
+
+ goto EvtDriverDeviceAddEnd;
+ }
+
+ //
+ // Configure a default queue for IO requests. This queue processes requests
+ // to read/write the simulated state.
+ //
+
+ WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&IoQueueConfig,
+ WdfIoQueueDispatchSequential);
+
+ IoQueueConfig.EvtIoDeviceControl = EvtIoDeviceControl;
+ Status = WdfIoQueueCreate(DeviceHandle,
+ &IoQueueConfig,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &Queue);
+
+ if (!NT_SUCCESS(Status)) {
+ DebugPrint(PLPOLICY_PRINT_ERROR,
+ "WdfIoQueueCreate() Failed! 0x%x\n",
+ Status);
+
+ goto EvtDriverDeviceAddEnd;
+ }
+
+ //
+ // Create device interface for this device. The interface will be
+ // enabled by the framework when StartDevice returns successfully.
+ // Clients of this driver will open this interface and send ioctls.
+ //
+
+ Status = WdfDeviceCreateDeviceInterface(DeviceHandle,
+ &GUID_DEVINTERFACE_POWERLIMIT_POLICY,
+ NULL);
+
+ if (!NT_SUCCESS(Status)) {
+ DebugPrint(PLPOLICY_PRINT_ERROR,
+ "WdfDeviceCreateDeviceInterface() Failed! 0x%x\n",
+ Status);
+
+ goto EvtDriverDeviceAddEnd;
+ }
+
+ //
+ // Ignore failures to initialize the device; the test cases will fail in
+ // this case.
+ //
+
+ DevExt = GetDeviceExtension(DeviceHandle);
+ InitializeListHead(&DevExt->RequestHeader);
+ DevExt->RequestCount = 0;
+ Status = STATUS_SUCCESS;
+
+EvtDriverDeviceAddEnd:
+ 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;
+ PLIST_ENTRY Link;
+ PDEVICE_REGISTRATION Registration;
+
+ PAGED_CODE();
+
+ DebugEnter();
+ DevExt = GetDeviceExtension(Object);
+ while (IsListEmpty(&DevExt->RequestHeader) == FALSE) {
+ Link = DevExt->RequestHeader.Flink;
+ Registration = CONTAINING_RECORD(Link, DEVICE_REGISTRATION, Link);
+ RemoveEntryList(&Registration->Link);
+ PoDeletePowerLimitRequest(Registration->PowerLimitRequest);
+ ExFreePoolWithTag(Registration, PLPOLICY_TAG);
+ }
+
+ DebugExit();
+ return;
+}
+
+_Use_decl_annotations_
+VOID
+EvtIoDeviceControl (
+ WDFQUEUE Queue,
+ WDFREQUEST Request,
+ size_t OutputBufferLength,
+ size_t InputBufferLength,
+ ULONG IoControlCode
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes an IOCTL sent to the PEP.
+
+Arguments:
+
+ Queue - Supplies a handle to the WDF queue object.
+
+ Request - Supplies a handle to the WDF request object for this request.
+
+ OuputBufferLength - Supplies the length of the output buffer, in bytes.
+
+ InputBufferLength - Supplies the length of the input buffer, in bytes.
+
+ IoControlCode - Supplies the IOCTL code being processes.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PPOWERLIMIT_POLICY_ATTRIBUTES Attributes;
+ ULONG BytesWritten;
+ PFDO_DATA DevExt;
+ WDFDEVICE Device;
+ UNICODE_STRING DeviceName;
+ PVOID InputBuffer;
+ PVOID OutputBuffer;
+ PPOWERLIMIT_POLICY_ATTRIBUTES QueryAttributeInput;
+ PPOWERLIMIT_POLICY_VALUES QueryValueInput;
+ ULONG RequestId;
+ PPOWERLIMIT_POLICY_VALUES SetInput;
+ ULONG SizeNeeded;
+ NTSTATUS Status;
+ PPOWERLIMIT_POLICY_VALUES Values;
+
+ DebugPrint(PLPOLICY_PRINT_TRACE,
+ "EvtIoDeviceControl: 0x%08x\n",
+ IoControlCode);
+
+ BytesWritten = 0;
+ OutputBuffer = NULL;
+ InputBuffer = NULL;
+ if (InputBufferLength > 0) {
+ Status = WdfRequestRetrieveInputBuffer(Request,
+ InputBufferLength,
+ &InputBuffer,
+ NULL);
+
+ if (!NT_SUCCESS(Status)) {
+ goto DeviceControlEnd;
+ }
+ }
+
+ if (OutputBufferLength > 0) {
+ Status = WdfRequestRetrieveOutputBuffer(Request,
+ OutputBufferLength,
+ &OutputBuffer,
+ NULL);
+
+ if (!NT_SUCCESS(Status)) {
+ goto DeviceControlEnd;
+ }
+ }
+
+ Device = WdfIoQueueGetDevice(Queue);
+ DevExt = GetDeviceExtension(Device);
+ switch (IoControlCode) {
+ case IOCTL_POWERLIMIT_POLICY_REGISTER:
+ if ((InputBufferLength == 0) || (InputBuffer == NULL)) {
+ Status = STATUS_INVALID_PARAMETER;
+ goto DeviceControlEnd;
+ }
+
+ if ((OutputBufferLength != sizeof(ULONG)) || (OutputBuffer == NULL)) {
+ Status = STATUS_INVALID_PARAMETER;
+ goto DeviceControlEnd;
+ }
+
+ Status = GetDeviceName(&DeviceName,
+ (PWCHAR)InputBuffer,
+ InputBufferLength);
+
+ if (!NT_SUCCESS(Status)) {
+ goto DeviceControlEnd;
+ }
+
+ Status = RegisterRequest(DevExt,
+ &DeviceName,
+ WdfDeviceWdmGetDeviceObject(Device),
+ &RequestId);
+
+ if (NT_SUCCESS(Status)) {
+ *(PULONG)OutputBuffer = RequestId;
+ BytesWritten = sizeof(ULONG);
+ }
+
+ break;
+
+ case IOCTL_POWERLIMIT_POLICY_UNREGISTER:
+ if (InputBufferLength < sizeof(ULONG)) {
+ Status = STATUS_INVALID_PARAMETER;
+ goto DeviceControlEnd;
+ }
+
+ RequestId = *(PULONG)InputBuffer;
+ Status = UnregisterRequest(DevExt, RequestId);
+
+ break;
+
+ case IOCTL_POWERLIMIT_POLICY_QUERY_ATTRIBUTES:
+ if (InputBufferLength < sizeof(POWERLIMIT_POLICY_ATTRIBUTES)) {
+ Status = STATUS_INVALID_PARAMETER;
+ goto DeviceControlEnd;
+ }
+
+ QueryAttributeInput = (PPOWERLIMIT_POLICY_ATTRIBUTES)InputBuffer;
+ SizeNeeded = FIELD_OFFSET(POWERLIMIT_POLICY_ATTRIBUTES,
+ Buffer[QueryAttributeInput->BufferCount]);
+
+ if ((OutputBufferLength < SizeNeeded) || (InputBufferLength < SizeNeeded)) {
+ Status = STATUS_INVALID_PARAMETER;
+ goto DeviceControlEnd;
+ }
+
+ Attributes = ExAllocatePool2(POOL_FLAG_PAGED, SizeNeeded, PLPOLICY_TAG);
+ if (Attributes == NULL) {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto DeviceControlEnd;
+ }
+
+ Attributes->RequestId = QueryAttributeInput->RequestId;
+ Attributes->BufferCount = QueryAttributeInput->BufferCount;
+ Status = QueryAttributes(Attributes->Buffer,
+ DevExt,
+ QueryAttributeInput->RequestId,
+ QueryAttributeInput->BufferCount);
+
+ if (NT_SUCCESS(Status)) {
+ RtlCopyMemory(OutputBuffer, Attributes, SizeNeeded);
+ BytesWritten = SizeNeeded;
+ }
+
+ ExFreePoolWithTag(Attributes, PLPOLICY_TAG);
+
+ break;
+
+ case IOCTL_POWERLIMIT_POLICY_QUERY_VALUES:
+ if (InputBufferLength < sizeof(POWERLIMIT_POLICY_VALUES)) {
+ Status = STATUS_INVALID_PARAMETER;
+ goto DeviceControlEnd;
+ }
+
+ QueryValueInput = (PPOWERLIMIT_POLICY_VALUES)InputBuffer;
+ SizeNeeded = FIELD_OFFSET(POWERLIMIT_POLICY_VALUES,
+ Buffer[QueryValueInput->BufferCount]);
+
+ if ((OutputBufferLength < SizeNeeded) || (InputBufferLength < SizeNeeded)) {
+ Status = STATUS_INVALID_PARAMETER;
+ goto DeviceControlEnd;
+ }
+
+ Values = ExAllocatePool2(POOL_FLAG_PAGED, SizeNeeded, PLPOLICY_TAG);
+ if (Values == NULL) {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto DeviceControlEnd;
+ }
+
+ //
+ // The input buffer contains which limits to read, copy them over before
+ // calling kernel API.
+ //
+
+ RtlCopyMemory(Values, QueryValueInput, SizeNeeded);
+ Status = QueryLimitValues(Values->Buffer,
+ DevExt,
+ QueryValueInput->RequestId,
+ QueryValueInput->BufferCount);
+
+ if (NT_SUCCESS(Status)) {
+ RtlCopyMemory(OutputBuffer, Values, SizeNeeded);
+ BytesWritten = SizeNeeded;
+ }
+
+ ExFreePoolWithTag(Values, PLPOLICY_TAG);
+
+ break;
+
+ case IOCTL_POWERLIMIT_POLICY_SET_VALUES:
+ if (InputBufferLength < sizeof(POWERLIMIT_POLICY_VALUES)) {
+ Status = STATUS_INVALID_PARAMETER;
+ goto DeviceControlEnd;
+ }
+
+ SetInput = (PPOWERLIMIT_POLICY_VALUES)InputBuffer;
+ SizeNeeded = FIELD_OFFSET(POWERLIMIT_POLICY_VALUES,
+ Buffer[SetInput->BufferCount]);
+
+ if (InputBufferLength < SizeNeeded) {
+ Status = STATUS_INVALID_PARAMETER;
+ goto DeviceControlEnd;
+ }
+
+ Status = SetLimitValues(DevExt,
+ SetInput->RequestId,
+ SetInput->BufferCount,
+ SetInput->Buffer);
+
+ break;
+
+ default:
+ Status = STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+DeviceControlEnd:
+ WdfRequestCompleteWithInformation(Request, Status, BytesWritten);
+ DebugExitStatus(Status);
+ return;
+}
+
+VOID
+EvtDriverUnload (
+ WDFDRIVER Driver
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called at driver unload to clean up any lingering thermal
+ requests.
+
+Arguments:
+
+ Driver - Supplies a pointer 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;
+}
+
+_Use_decl_annotations_
+NTSTATUS
+GetDeviceName (
+ PUNICODE_STRING DeviceName,
+ PWCHAR Buffer,
+ SIZE_T BufferLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine extracts a device name from an IOCTL input buffer, being
+ careful to validate the name is well formed.
+
+Arguments:
+
+ DeviceName - Supplies a UNICODE_STRING to initialize with the device name.
+
+ Buffer - Supplies the buffer containing the device name.
+
+ BufferLength - Supplies the length of the buffer containing the device name,
+ in bytes.
+
+Return Value:
+
+ NTSTATUS.
+
+--*/
+
+{
+
+ size_t Length;
+ NTSTATUS Status;
+
+ Status = RtlStringCchLengthW(Buffer, BufferLength / sizeof(WCHAR), &Length);
+ if (!NT_SUCCESS(Status)) {
+ goto GetDeviceNameEnd;
+ }
+
+ if (Length > NTSTRSAFE_UNICODE_STRING_MAX_CCH) {
+ Status = STATUS_INVALID_PARAMETER;
+ goto GetDeviceNameEnd;
+ }
+
+ DeviceName->Buffer = Buffer;
+ DeviceName->Length = (USHORT)(Length * sizeof(WCHAR));
+ DeviceName->MaximumLength = (USHORT)(Length * sizeof(WCHAR));
+ Status = STATUS_SUCCESS;
+
+GetDeviceNameEnd:
+ return Status;
+}