[ACPI] Remove section assignment from IOCTL handlers (#7829)

Fix a bug introduced in 5070e8960a.

CORE-17256

- These handlers must be memory resident. Otherwise,
  this would cause a page fault that needs to be resolved.
  Low-level storage drivers could evaluate ACPI control
  methods while the device's IRP queue has been paused.

- Minor code enhancements.
This commit is contained in:
Dmitry Borisov 2025-05-06 02:42:11 +06:00 committed by GitHub
parent d1f9e06a4f
commit 45b928f8bc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 21 additions and 109 deletions

View file

@ -6,10 +6,10 @@
#endif /* UNIT_TEST */
#define AcpiVerifyInBuffer(Stack, Length) \
((Stack)->Parameters.DeviceIoControl.InputBufferLength >= Length)
((Stack)->Parameters.DeviceIoControl.InputBufferLength >= (Length))
#define AcpiVerifyOutBuffer(Stack, Length) \
((Stack)->Parameters.DeviceIoControl.OutputBufferLength >= Length)
((Stack)->Parameters.DeviceIoControl.OutputBufferLength >= (Length))
#define TAG_ACPI_PARAMETERS_LIST 'OpcA'
#define TAG_ACPI_PACKAGE_LIST 'PpcA'
@ -31,7 +31,6 @@
* into a string method argument.
*/
static
CODE_SEG("PAGE")
NTSTATUS
EvalConvertObjectReference(
_Out_ PACPI_METHOD_ARGUMENT Argument,
@ -40,8 +39,6 @@ EvalConvertObjectReference(
ACPI_BUFFER OutName;
ACPI_STATUS AcpiStatus;
PAGED_CODE();
Argument->Type = ACPI_METHOD_ARGUMENT_STRING;
Argument->DataLength = ACPI_OBJECT_NAME_LENGTH;
@ -52,7 +49,7 @@ EvalConvertObjectReference(
AcpiStatus = AcpiGetName(Reference->Reference.Handle, ACPI_SINGLE_NAME, &OutName);
if (!ACPI_SUCCESS(AcpiStatus))
{
DPRINT1("AcpiGetName() failed on %p with status 0x%04lx\n",
DPRINT1("AcpiGetName() failed on %p with status 0x%04x\n",
Reference->Reference.Handle,
AcpiStatus);
@ -68,7 +65,6 @@ EvalConvertObjectReference(
* based on the type of an ACPI_OBJECT structure.
*/
static
CODE_SEG("PAGE")
NTSTATUS
EvalGetElementSize(
_In_ ACPI_OBJECT* Obj,
@ -79,8 +75,6 @@ EvalGetElementSize(
ULONG TotalCount, TotalLength;
NTSTATUS Status;
PAGED_CODE();
if (Depth >= ACPI_MAX_PACKAGE_DEPTH)
{
ASSERT(FALSE);
@ -150,7 +144,7 @@ EvalGetElementSize(
default:
{
DPRINT1("Unsupported element type %lu\n", Obj->Type);
DPRINT1("Unsupported element type %u\n", Obj->Type);
return STATUS_UNSUCCESSFUL;
}
}
@ -167,7 +161,6 @@ EvalGetElementSize(
* @brief Performs translation from the supplied ACPI_OBJECT structure into a method argument.
*/
static
CODE_SEG("PAGE")
NTSTATUS
EvalConvertEvaluationResults(
_Out_ ACPI_METHOD_ARGUMENT* Argument,
@ -177,8 +170,6 @@ EvalConvertEvaluationResults(
ACPI_METHOD_ARGUMENT *Ptr;
NTSTATUS Status;
PAGED_CODE();
if (Depth >= ACPI_MAX_PACKAGE_DEPTH)
{
ASSERT(FALSE);
@ -259,7 +250,7 @@ EvalConvertEvaluationResults(
default:
{
DPRINT1("Unsupported element type %lu\n", Obj->Type);
DPRINT1("Unsupported element type %u\n", Obj->Type);
return STATUS_UNSUCCESSFUL;
}
}
@ -271,7 +262,6 @@ EvalConvertEvaluationResults(
* @brief Returns the number of sub-objects (elements) in a package.
*/
static
CODE_SEG("PAGE")
ULONG
EvalGetPackageCount(
_In_ PACPI_METHOD_ARGUMENT Package,
@ -281,8 +271,6 @@ EvalGetPackageCount(
ACPI_METHOD_ARGUMENT* Ptr;
ULONG TotalLength = 0, TotalCount = 0;
PAGED_CODE();
/* Empty package */
if (DataLength < ACPI_METHOD_ARGUMENT_LENGTH(0) || Package->Argument == 0)
return 0;
@ -303,7 +291,6 @@ EvalGetPackageCount(
* @brief Performs translation from the supplied method argument into an ACPI_OBJECT structure.
*/
static
CODE_SEG("PAGE")
NTSTATUS
EvalConvertParameterObjects(
_Out_ ACPI_OBJECT* Arg,
@ -312,7 +299,6 @@ EvalConvertParameterObjects(
_In_ PIO_STACK_LOCATION IoStack,
_In_ ULONG Offset)
{
PAGED_CODE();
if (Depth >= ACPI_MAX_PACKAGE_DEPTH)
{
@ -388,7 +374,7 @@ EvalConvertParameterObjects(
Status = RtlULongMult(Arg->Package.Count, sizeof(*Arg), &PackageSize);
if (!NT_SUCCESS(Status))
{
DPRINT1("Invalid package count 0x%lx\n", Arg->Package.Count);
DPRINT1("Invalid package count 0x%x\n", Arg->Package.Count);
return STATUS_ACPI_INCORRECT_ARGUMENT_COUNT;
}
@ -431,7 +417,6 @@ EvalConvertParameterObjects(
* @brief Creates a counted array of ACPI_OBJECTs from the given input buffer.
*/
static
CODE_SEG("PAGE")
NTSTATUS
EvalCreateParametersList(
_In_ PIRP Irp,
@ -441,8 +426,6 @@ EvalCreateParametersList(
{
ACPI_OBJECT* Arg;
PAGED_CODE();
if (!AcpiVerifyInBuffer(IoStack, RTL_SIZEOF_THROUGH_FIELD(ACPI_EVAL_INPUT_BUFFER, Signature)))
{
DPRINT1("Buffer too small\n");
@ -537,7 +520,7 @@ EvalCreateParametersList(
Status = RtlULongMult(ParamList->Count, sizeof(*Arg), &ArgumentsSize);
if (!NT_SUCCESS(Status))
{
DPRINT1("Invalid argument count 0x%lx\n", ParamList->Count);
DPRINT1("Invalid argument count 0x%x\n", ParamList->Count);
return STATUS_ACPI_INCORRECT_ARGUMENT_COUNT;
}
@ -593,7 +576,6 @@ EvalCreateParametersList(
* @brief Deallocates the memory for all sub-objects (elements) in a package.
*/
static
CODE_SEG("PAGE")
VOID
EvalFreeParameterArgument(
_In_ ACPI_OBJECT* Arg,
@ -601,8 +583,6 @@ EvalFreeParameterArgument(
{
ULONG i;
PAGED_CODE();
if (Depth >= ACPI_MAX_PACKAGE_DEPTH)
{
ASSERT(FALSE);
@ -626,7 +606,6 @@ EvalFreeParameterArgument(
* @brief Deallocates the given array of ACPI_OBJECTs.
*/
static
CODE_SEG("PAGE")
VOID
EvalFreeParametersList(
_In_ ACPI_OBJECT_LIST* ParamList)
@ -634,8 +613,6 @@ EvalFreeParametersList(
ACPI_OBJECT* Arg;
ULONG i;
PAGED_CODE();
Arg = ParamList->Pointer;
for (i = 0; i < ParamList->Count; i++)
{
@ -649,13 +626,10 @@ EvalFreeParametersList(
* @brief Converts the provided value of ACPI_STATUS to NTSTATUS return value.
*/
static
CODE_SEG("PAGE")
NTSTATUS
EvalAcpiStatusToNtStatus(
_In_ ACPI_STATUS AcpiStatus)
{
PAGED_CODE();
if (ACPI_ENV_EXCEPTION(AcpiStatus))
{
switch (AcpiStatus)
@ -680,7 +654,7 @@ EvalAcpiStatusToNtStatus(
return STATUS_ACPI_STACK_OVERFLOW;
default:
break;
goto DefaultStatus;
}
}
@ -692,10 +666,11 @@ EvalAcpiStatusToNtStatus(
return STATUS_ACPI_INCORRECT_ARGUMENT_COUNT;
default:
break;
goto DefaultStatus;
}
}
DefaultStatus:
return STATUS_UNSUCCESSFUL;
}
@ -703,7 +678,6 @@ EvalAcpiStatusToNtStatus(
* @brief Evaluates an ACPI namespace object.
*/
static
CODE_SEG("PAGE")
ACPI_STATUS
EvalEvaluateObject(
_In_ PPDO_DEVICE_DATA DeviceData,
@ -713,9 +687,7 @@ EvalEvaluateObject(
{
CHAR MethodName[ACPI_OBJECT_NAME_LENGTH];
PAGED_CODE();
RtlCopyMemory(MethodName, EvalInputBuffer->MethodName, ACPI_OBJECT_NAME_LENGTH);
RtlCopyMemory(MethodName, EvalInputBuffer->MethodName, ACPI_OBJECT_NAME_LENGTH - 1);
MethodName[ACPI_OBJECT_NAME_LENGTH - 1] = ANSI_NULL;
return AcpiEvaluateObject(DeviceData->AcpiHandle, MethodName, ParamList, ReturnBuffer);
@ -725,7 +697,6 @@ EvalEvaluateObject(
* @brief Writes the results from the evaluation into the output IRP buffer.
*/
static
CODE_SEG("PAGE")
NTSTATUS
EvalCreateOutputArguments(
_In_ PIRP Irp,
@ -738,8 +709,6 @@ EvalCreateOutputArguments(
NTSTATUS Status;
ULONG Count;
PAGED_CODE();
/* If we didn't get anything back then we're done */
if (!ReturnBuffer->Pointer || ReturnBuffer->Length == 0)
return STATUS_SUCCESS;
@ -790,7 +759,7 @@ EvalCreateOutputArguments(
return STATUS_SUCCESS;
}
CODE_SEG("PAGE")
/* IOCTL handlers for asynchronous evaluation requests must not be paged */
NTSTATUS
NTAPI
Bus_PDO_EvalMethod(
@ -804,8 +773,6 @@ Bus_PDO_EvalMethod(
NTSTATUS Status;
ACPI_BUFFER ReturnBuffer = { ACPI_ALLOCATE_BUFFER, NULL };
PAGED_CODE();
IoStack = IoGetCurrentIrpStackLocation(Irp);
EvalInputBuffer = Irp->AssociatedIrp.SystemBuffer;
@ -820,7 +787,7 @@ Bus_PDO_EvalMethod(
if (!ACPI_SUCCESS(AcpiStatus))
{
DPRINT("Query method '%.4s' failed on %p with status 0x%04lx\n",
DPRINT("Query method '%.4s' failed on %p with status 0x%04x\n",
EvalInputBuffer->MethodName,
DeviceData->AcpiHandle,
AcpiStatus);
@ -835,27 +802,3 @@ Bus_PDO_EvalMethod(
return Status;
}
#ifndef UNIT_TEST
CODE_SEG("PAGE")
VOID
NTAPI
Bus_PDO_EvalMethodWorker(
_In_ PVOID Parameter)
{
PEVAL_WORKITEM_DATA WorkItemData = Parameter;
NTSTATUS Status;
PIRP Irp;
PAGED_CODE();
Irp = WorkItemData->Irp;
Status = Bus_PDO_EvalMethod(WorkItemData->DeviceData, Irp);
ExFreePoolWithTag(WorkItemData, 'ipcA');
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
#endif /* UNIT_TEST */

View file

@ -73,13 +73,6 @@ typedef struct _FDO_DEVICE_DATA
} FDO_DEVICE_DATA, *PFDO_DEVICE_DATA;
typedef struct _EVAL_WORKITEM_DATA
{
PPDO_DEVICE_DATA DeviceData;
PIRP Irp;
WORK_QUEUE_ITEM WorkQueueItem;
} EVAL_WORKITEM_DATA, *PEVAL_WORKITEM_DATA;
#define FDO_FROM_PDO(pdoData) \
((PFDO_DEVICE_DATA) (pdoData)->ParentFdo->DeviceExtension)
@ -100,10 +93,6 @@ NTSTATUS
ACPIEnumerateDevices(
PFDO_DEVICE_DATA DeviceExtension);
CODE_SEG("PAGE")
WORKER_THREAD_ROUTINE Bus_PDO_EvalMethodWorker;
CODE_SEG("PAGE")
NTSTATUS
NTAPI
Bus_PDO_EvalMethod(

View file

@ -243,36 +243,16 @@ ACPIDispatchDeviceControl(
{
ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
if (KeGetCurrentIrql() == DISPATCH_LEVEL)
{
PEVAL_WORKITEM_DATA workItemData;
workItemData = ExAllocatePoolUninitialized(NonPagedPool,
sizeof(*workItemData),
'ipcA');
if (!workItemData)
{
status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
workItemData->Irp = Irp;
workItemData->DeviceData = (PPDO_DEVICE_DATA)commonData;
ExInitializeWorkItem(&workItemData->WorkQueueItem,
Bus_PDO_EvalMethodWorker,
workItemData);
ExQueueWorkItem(&workItemData->WorkQueueItem, DelayedWorkQueue);
status = STATUS_PENDING;
break;
}
__fallthrough;
status = Bus_PDO_EvalMethod((PPDO_DEVICE_DATA)commonData, Irp);
break;
}
case IOCTL_ACPI_EVAL_METHOD:
case IOCTL_ACPI_EVAL_METHOD:
{
status = Bus_PDO_EvalMethod((PPDO_DEVICE_DATA)commonData,
Irp);
break;
ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
status = Bus_PDO_EvalMethod((PPDO_DEVICE_DATA)commonData, Irp);
break;
}
case IOCTL_GET_SYS_BUTTON_CAPS: