Beispiel #1
0
NTSTATUS
NTAPI
Bus_PDO_EvalMethod(PPDO_DEVICE_DATA DeviceData,
                   PIRP Irp)
{
  ULONG Signature;
  NTSTATUS Status;
  ACPI_OBJECT_LIST ParamList;
  PACPI_EVAL_INPUT_BUFFER EvalInputBuff = Irp->AssociatedIrp.SystemBuffer;
  ACPI_BUFFER RetBuff = {ACPI_ALLOCATE_BUFFER, NULL};
  PACPI_EVAL_OUTPUT_BUFFER OutputBuf;
  PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
  ACPI_EVAL_INPUT_BUFFER_SIMPLE_INTEGER *SimpleInt;
  ACPI_EVAL_INPUT_BUFFER_SIMPLE_STRING *SimpleStr;

  if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG))
      return STATUS_INVALID_PARAMETER;

  Signature = *((PULONG)Irp->AssociatedIrp.SystemBuffer);

  switch (Signature)
  {
     case ACPI_EVAL_INPUT_BUFFER_SIGNATURE:
        if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ACPI_EVAL_INPUT_BUFFER))
            return STATUS_INVALID_PARAMETER;

        ParamList.Count = 0;
        break;

     case ACPI_EVAL_INPUT_BUFFER_SIMPLE_INTEGER_SIGNATURE:
        SimpleInt = Irp->AssociatedIrp.SystemBuffer;

        if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ACPI_EVAL_INPUT_BUFFER_SIMPLE_INTEGER))
            return STATUS_INVALID_PARAMETER;

        ParamList.Count = 1;

        ParamList.Pointer = ExAllocatePoolWithTag(NonPagedPool, sizeof(ACPI_OBJECT), 'OpcA');
        if (!ParamList.Pointer) return STATUS_INSUFFICIENT_RESOURCES;

        ParamList.Pointer[0].Type = ACPI_TYPE_INTEGER;
        ParamList.Pointer[0].Integer.Value = SimpleInt->IntegerArgument;
        break;

     case ACPI_EVAL_INPUT_BUFFER_SIMPLE_STRING_SIGNATURE:
        SimpleStr = Irp->AssociatedIrp.SystemBuffer;

        if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ACPI_EVAL_INPUT_BUFFER_SIMPLE_STRING))
            return STATUS_INVALID_PARAMETER;

        ParamList.Count = 1;

        ParamList.Pointer = ExAllocatePoolWithTag(NonPagedPool, sizeof(ACPI_OBJECT), 'OpcA');
        if (!ParamList.Pointer) return STATUS_INSUFFICIENT_RESOURCES;

        ParamList.Pointer[0].String.Pointer = (CHAR*)SimpleStr->String;
        ParamList.Pointer[0].String.Length = SimpleStr->StringLength;
        break;

     default:
        DPRINT1("Unsupported input buffer signature: %d\n", Signature);
        return STATUS_NOT_IMPLEMENTED;
  }

  Status = AcpiEvaluateObject(DeviceData->AcpiHandle,
                              (CHAR*)EvalInputBuff->MethodName,
                              &ParamList,
                              &RetBuff);

  if (ParamList.Count != 0)
      ExFreePoolWithTag(ParamList.Pointer, 'OpcA');

  if (ACPI_SUCCESS(Status))
  {
      ACPI_OBJECT *Obj = RetBuff.Pointer;
      ULONG ExtraParamLength;

      /* If we didn't get anything back then we're done */
      if (!RetBuff.Pointer || RetBuff.Length == 0)
          return STATUS_SUCCESS;

      switch (Obj->Type)
      {
          case ACPI_TYPE_INTEGER:
             ExtraParamLength = sizeof(ULONG);
             break;

          case ACPI_TYPE_STRING:
             ExtraParamLength = Obj->String.Length;
             break;

          case ACPI_TYPE_BUFFER:
             ExtraParamLength = Obj->Buffer.Length;
             break;

          case ACPI_TYPE_PACKAGE:
             DPRINT1("ACPI_TYPE_PACKAGE not supported yet!\n");
             return STATUS_UNSUCCESSFUL;

          default:
             ASSERT(FALSE);
             return STATUS_UNSUCCESSFUL;
      }

      /* Enough space for a ULONG is always included */
      if (ExtraParamLength >= sizeof(ULONG))
          ExtraParamLength -= sizeof(ULONG);
      else
          ExtraParamLength = 0;

      OutputBuf = ExAllocatePoolWithTag(NonPagedPool, sizeof(ACPI_EVAL_OUTPUT_BUFFER) +
                                               ExtraParamLength, 'BpcA');
      if (!OutputBuf) return STATUS_INSUFFICIENT_RESOURCES;

      OutputBuf->Signature = ACPI_EVAL_OUTPUT_BUFFER_SIGNATURE;
      OutputBuf->Length = ExtraParamLength + sizeof(ACPI_METHOD_ARGUMENT);
      OutputBuf->Count = 1;

      switch (Obj->Type)
      {
          case ACPI_TYPE_INTEGER:
             ACPI_METHOD_SET_ARGUMENT_INTEGER(OutputBuf->Argument, Obj->Integer.Value);
             break;

          case ACPI_TYPE_STRING:
             ACPI_METHOD_SET_ARGUMENT_STRING(OutputBuf->Argument, Obj->String.Pointer);
             break;

          case ACPI_TYPE_BUFFER:
             ACPI_METHOD_SET_ARGUMENT_BUFFER(OutputBuf->Argument, Obj->Buffer.Pointer, Obj->Buffer.Length);
             break;

          case ACPI_TYPE_PACKAGE:
             DPRINT1("ACPI_TYPE_PACKAGE not supported yet!\n");
             return STATUS_UNSUCCESSFUL;

          default:
             ASSERT(FALSE);
             return STATUS_UNSUCCESSFUL;
      }

      if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(ACPI_EVAL_OUTPUT_BUFFER) +
                                                                  ExtraParamLength)
      {
          RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, OutputBuf, sizeof(ACPI_EVAL_OUTPUT_BUFFER) +
                                                                    ExtraParamLength);
          Irp->IoStatus.Information = sizeof(ACPI_EVAL_OUTPUT_BUFFER) + ExtraParamLength;
          ExFreePoolWithTag(OutputBuf, 'BpcA');
          return STATUS_SUCCESS;
      }
      else
      {
          ExFreePoolWithTag(OutputBuf, 'BpcA');
          return STATUS_BUFFER_TOO_SMALL;
      }
  }
  else
  {
      DPRINT1("Query method %s failed on %p\n", EvalInputBuff->MethodName, DeviceData->AcpiHandle);
      return STATUS_UNSUCCESSFUL; 
  }
}
NTSTATUS
Acpi_EvaluateUcsiDsm (
    _In_ PACPI_CONTEXT AcpiCtx,
    _In_ ULONG FunctionIndex,
    _Outptr_opt_ PACPI_EVAL_OUTPUT_BUFFER* Output
    )
/*++

    N.B. Caller is expected to free the Output buffer.

--*/
{
    NTSTATUS status;
    WDFDEVICE device;
    WDFMEMORY inputMemory;
    WDF_MEMORY_DESCRIPTOR inputMemDesc;
    PACPI_EVAL_INPUT_BUFFER_COMPLEX inputBuffer;
    size_t inputBufferSize;
    size_t inputArgumentBufferSize;
    PACPI_METHOD_ARGUMENT argument;
    WDF_MEMORY_DESCRIPTOR outputMemDesc;
    PACPI_EVAL_OUTPUT_BUFFER outputBuffer;
    size_t outputBufferSize;
    size_t outputArgumentBufferSize;
    WDF_OBJECT_ATTRIBUTES attributes;
    WDF_REQUEST_SEND_OPTIONS sendOptions;

    PAGED_CODE();

    TRACE_FUNC_ENTRY(TRACE_FLAG_ACPI);

    device = Context_GetWdfDevice(AcpiCtx);
    inputMemory = WDF_NO_HANDLE;
    outputBuffer = nullptr;

    inputArgumentBufferSize =
        ACPI_METHOD_ARGUMENT_LENGTH(sizeof(GUID)) +
        ACPI_METHOD_ARGUMENT_LENGTH(sizeof(ULONG)) +
        ACPI_METHOD_ARGUMENT_LENGTH(sizeof(ULONG)) +
        ACPI_METHOD_ARGUMENT_LENGTH(0);

    inputBufferSize =
        FIELD_OFFSET(ACPI_EVAL_INPUT_BUFFER_COMPLEX, Argument) +
        inputArgumentBufferSize;

    WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
    attributes.ParentObject = device;

    status = WdfMemoryCreate(&attributes,
                             NonPagedPoolNx,
                             0,
                             inputBufferSize,
                             &inputMemory,
                             (PVOID*) &inputBuffer);

    if (!NT_SUCCESS(status))
    {
        TRACE_ERROR(TRACE_FLAG_ACPI, "[Device: 0x%p] WdfMemoryCreate failed for %Iu bytes - %!STATUS!", device, inputBufferSize, status);
        goto Exit;
    }

    RtlZeroMemory(inputBuffer, inputBufferSize);

    inputBuffer->Signature = ACPI_EVAL_INPUT_BUFFER_COMPLEX_SIGNATURE;
    inputBuffer->Size = (ULONG) inputArgumentBufferSize;
    inputBuffer->ArgumentCount = 4;
    inputBuffer->MethodNameAsUlong = (ULONG) 'MSD_';

    argument = &(inputBuffer->Argument[0]);
    ACPI_METHOD_SET_ARGUMENT_BUFFER(argument,
                                    &GUID_UCSI_DSM,
                                    sizeof(GUID_UCSI_DSM));

    argument = ACPI_METHOD_NEXT_ARGUMENT(argument);
    ACPI_METHOD_SET_ARGUMENT_INTEGER(argument, UCSI_DSM_REVISION);

    argument = ACPI_METHOD_NEXT_ARGUMENT(argument);
    ACPI_METHOD_SET_ARGUMENT_INTEGER(argument, FunctionIndex);

    argument = ACPI_METHOD_NEXT_ARGUMENT(argument);
    argument->Type = ACPI_METHOD_ARGUMENT_PACKAGE_EX;
    argument->DataLength = 0;

    outputArgumentBufferSize = ACPI_METHOD_ARGUMENT_LENGTH(sizeof(ULONG));
    outputBufferSize =
        FIELD_OFFSET(ACPI_EVAL_OUTPUT_BUFFER, Argument) +
        outputArgumentBufferSize;

    outputBuffer = (PACPI_EVAL_OUTPUT_BUFFER) ExAllocatePoolWithTag(NonPagedPoolNx,
                                                                    outputBufferSize,
                                                                    TAG_UCSI);

    if (outputBuffer == nullptr)
    {
        status = STATUS_INSUFFICIENT_RESOURCES;
        TRACE_ERROR(TRACE_FLAG_ACPI, "[Device: 0x%p] ExAllocatePoolWithTag failed for %Iu bytes", device, outputBufferSize);
        goto Exit;
    }

    RtlZeroMemory(outputBuffer, outputBufferSize);

    WDF_MEMORY_DESCRIPTOR_INIT_HANDLE(&inputMemDesc, inputMemory, NULL);
    WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&outputMemDesc, outputBuffer, (ULONG) outputBufferSize);

    WDF_REQUEST_SEND_OPTIONS_INIT(&sendOptions, WDF_REQUEST_SEND_OPTION_SYNCHRONOUS);
    WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&sendOptions,
                                         WDF_REL_TIMEOUT_IN_MS(UCSI_DSM_EXECUTION_TIMEOUT_IN_MS));

    status = WdfIoTargetSendInternalIoctlSynchronously(
                 WdfDeviceGetIoTarget(device),
                 NULL,
                 IOCTL_ACPI_EVAL_METHOD,
                 &inputMemDesc,
                 &outputMemDesc,
                 &sendOptions,
                 NULL);

    if (!NT_SUCCESS(status))
    {
        TRACE_ERROR(TRACE_FLAG_ACPI, "[Device: 0x%p] IOCTL_ACPI_EVAL_METHOD for _DSM failed - %!STATUS!", device, status);
        goto Exit;
    }

    if (outputBuffer->Signature != ACPI_EVAL_OUTPUT_BUFFER_SIGNATURE)
    {
        TRACE_ERROR(TRACE_FLAG_ACPI, "[Device: 0x%p] ACPI_EVAL_OUTPUT_BUFFER signature is incorrect", device);
        status = STATUS_ACPI_INVALID_DATA;
        goto Exit;
    }

Exit:

    if (inputMemory != WDF_NO_HANDLE)
    {
        WdfObjectDelete(inputMemory);
    }

    if (!NT_SUCCESS(status) || (Output == nullptr))
    {
        if (outputBuffer)
        {
            ExFreePoolWithTag(outputBuffer, TAG_UCSI);
        }
    }
    else
    {
        *Output = outputBuffer;
    }

    TRACE_FUNC_EXIT(TRACE_FLAG_ACPI);

    return status;
}