diff options
| author | Jakob Lichtenberg (170957) <[email protected]> | 2024-06-28 11:43:03 -0700 |
|---|---|---|
| committer | Jakob Lichtenberg (170957) <[email protected]> | 2024-06-28 11:43:03 -0700 |
| commit | 341564fbc34d7521d03da4e91a0d4c2be9656410 (patch) | |
| tree | eb73dfda8e7c2cd3450c7d1cc8a73beafb914b0e /powerlimit/plclient/plclient.c | |
| parent | 57d4b2b5143a99d6e3a39100d183e26cac51da5b (diff) | |
| parent | b3af8c8f9bd508f54075da2f2516b31d05cd52c8 (diff) | |
Merge branch 'main' into user/jakobl/add_templatesuser/jakobl/add_templates
Diffstat (limited to 'powerlimit/plclient/plclient.c')
| -rw-r--r-- | powerlimit/plclient/plclient.c | 451 |
1 files changed, 451 insertions, 0 deletions
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; +} |
