1 #ifndef UNIT_TEST 2 #include "precomp.h" 3 4 #define NDEBUG 5 #include <debug.h> 6 #endif /* UNIT_TEST */ 7 8 #define AcpiVerifyInBuffer(Stack, Length) \ 9 ((Stack)->Parameters.DeviceIoControl.InputBufferLength >= Length) 10 11 #define AcpiVerifyOutBuffer(Stack, Length) \ 12 ((Stack)->Parameters.DeviceIoControl.OutputBufferLength >= Length) 13 14 #define TAG_ACPI_PARAMETERS_LIST 'OpcA' 15 #define TAG_ACPI_PACKAGE_LIST 'PpcA' 16 17 /** 18 * Null terminated ACPI name for the object. 19 * For example, _DSM, LNKB, etc. 20 */ 21 #define ACPI_OBJECT_NAME_LENGTH (4 + 1) 22 23 /** 24 * Maximum number of nested package structures supported by the driver. 25 * This should be enough to cover all the existing ACPI methods. 26 */ 27 #define ACPI_MAX_PACKAGE_DEPTH 5 28 29 /** 30 * @brief Performs translation from the supplied object reference 31 * into a string method argument. 32 */ 33 static 34 CODE_SEG("PAGE") 35 NTSTATUS 36 EvalConvertObjectReference( 37 _Out_ PACPI_METHOD_ARGUMENT Argument, 38 _In_ ACPI_OBJECT* Reference) 39 { 40 ACPI_BUFFER OutName; 41 ACPI_STATUS AcpiStatus; 42 43 PAGED_CODE(); 44 45 Argument->Type = ACPI_METHOD_ARGUMENT_STRING; 46 Argument->DataLength = ACPI_OBJECT_NAME_LENGTH; 47 48 /* Convert the object handle to an ACPI name */ 49 OutName.Length = ACPI_OBJECT_NAME_LENGTH; 50 OutName.Pointer = &Argument->Data[0]; 51 52 AcpiStatus = AcpiGetName(Reference->Reference.Handle, ACPI_SINGLE_NAME, &OutName); 53 if (!ACPI_SUCCESS(AcpiStatus)) 54 { 55 DPRINT1("AcpiGetName() failed on %p with status 0x%04lx\n", 56 Reference->Reference.Handle, 57 AcpiStatus); 58 59 ASSERT(FALSE); 60 return STATUS_UNSUCCESSFUL; 61 } 62 63 return STATUS_SUCCESS; 64 } 65 66 /** 67 * @brief Calculates the number of bytes needed for returned method argument 68 * based on the type of an ACPI_OBJECT structure. 69 */ 70 static 71 CODE_SEG("PAGE") 72 NTSTATUS 73 EvalGetElementSize( 74 _In_ ACPI_OBJECT* Obj, 75 _In_ ULONG Depth, 76 _Out_opt_ PULONG Count, 77 _Out_ PULONG Size) 78 { 79 ULONG TotalCount, TotalLength; 80 NTSTATUS Status; 81 82 PAGED_CODE(); 83 84 if (Depth >= ACPI_MAX_PACKAGE_DEPTH) 85 { 86 ASSERT(FALSE); 87 return STATUS_UNSUCCESSFUL; 88 } 89 90 switch (Obj->Type) 91 { 92 case ACPI_TYPE_INTEGER: 93 { 94 TotalLength = ACPI_METHOD_ARGUMENT_LENGTH(sizeof(ULONG)); 95 TotalCount = 1; 96 break; 97 } 98 99 case ACPI_TYPE_STRING: 100 { 101 TotalLength = ACPI_METHOD_ARGUMENT_LENGTH(Obj->String.Length + sizeof(UCHAR)); 102 TotalCount = 1; 103 break; 104 } 105 106 case ACPI_TYPE_BUFFER: 107 { 108 TotalLength = ACPI_METHOD_ARGUMENT_LENGTH(Obj->Buffer.Length); 109 TotalCount = 1; 110 break; 111 } 112 113 case ACPI_TYPE_PACKAGE: 114 { 115 ULONG i, TotalPackageLength; 116 117 /* Get the size of the current packet */ 118 TotalPackageLength = 0; 119 for (i = 0; i < Obj->Package.Count; i++) 120 { 121 ULONG ElementSize; 122 123 Status = EvalGetElementSize(&Obj->Package.Elements[i], 124 Depth + 1, 125 NULL, 126 &ElementSize); 127 if (!NT_SUCCESS(Status)) 128 return Status; 129 130 TotalPackageLength += ElementSize; 131 } 132 133 /* Check if we need to wrap the list of elements into a package */ 134 if (Depth > 0) 135 { 136 TotalPackageLength = ACPI_METHOD_ARGUMENT_LENGTH(TotalPackageLength); 137 } 138 139 TotalLength = TotalPackageLength; 140 TotalCount = Obj->Package.Count; 141 break; 142 } 143 144 case ACPI_TYPE_LOCAL_REFERENCE: 145 { 146 TotalLength = ACPI_METHOD_ARGUMENT_LENGTH(ACPI_OBJECT_NAME_LENGTH); 147 TotalCount = 1; 148 break; 149 } 150 151 default: 152 { 153 DPRINT1("Unsupported element type %lu\n", Obj->Type); 154 return STATUS_UNSUCCESSFUL; 155 } 156 } 157 158 if (Count) 159 *Count = TotalCount; 160 161 *Size = TotalLength; 162 163 return STATUS_SUCCESS; 164 } 165 166 /** 167 * @brief Performs translation from the supplied ACPI_OBJECT structure into a method argument. 168 */ 169 static 170 CODE_SEG("PAGE") 171 NTSTATUS 172 EvalConvertEvaluationResults( 173 _Out_ ACPI_METHOD_ARGUMENT* Argument, 174 _In_ ULONG Depth, 175 _In_ ACPI_OBJECT* Obj) 176 { 177 ACPI_METHOD_ARGUMENT *Ptr; 178 NTSTATUS Status; 179 180 PAGED_CODE(); 181 182 if (Depth >= ACPI_MAX_PACKAGE_DEPTH) 183 { 184 ASSERT(FALSE); 185 return STATUS_UNSUCCESSFUL; 186 } 187 188 Ptr = Argument; 189 switch (Obj->Type) 190 { 191 case ACPI_TYPE_INTEGER: 192 { 193 ACPI_METHOD_SET_ARGUMENT_INTEGER(Ptr, Obj->Integer.Value); 194 break; 195 } 196 197 case ACPI_TYPE_STRING: 198 { 199 ACPI_METHOD_SET_ARGUMENT_STRING(Ptr, Obj->String.Pointer); 200 break; 201 } 202 203 case ACPI_TYPE_BUFFER: 204 { 205 ACPI_METHOD_SET_ARGUMENT_BUFFER(Ptr, Obj->Buffer.Pointer, Obj->Buffer.Length); 206 break; 207 } 208 209 case ACPI_TYPE_PACKAGE: 210 { 211 ULONG i; 212 213 /* Check if we need to wrap the list of elements into a package */ 214 if (Depth > 0) 215 { 216 ULONG TotalPackageLength; 217 218 /* Get the size of the current packet */ 219 TotalPackageLength = 0; 220 for (i = 0; i < Obj->Package.Count; i++) 221 { 222 ULONG ElementSize; 223 224 Status = EvalGetElementSize(&Obj->Package.Elements[i], 225 Depth + 1, 226 NULL, 227 &ElementSize); 228 if (!NT_SUCCESS(Status)) 229 return Status; 230 231 TotalPackageLength += ElementSize; 232 } 233 234 /* Start a new package */ 235 Argument->Type = ACPI_METHOD_ARGUMENT_PACKAGE; 236 Argument->DataLength = TotalPackageLength; 237 238 Ptr = (PACPI_METHOD_ARGUMENT)Ptr->Data; 239 } 240 241 for (i = 0; i < Obj->Package.Count; i++) 242 { 243 Status = EvalConvertEvaluationResults(Ptr, Depth + 1, &Obj->Package.Elements[i]); 244 if (!NT_SUCCESS(Status)) 245 return Status; 246 247 Ptr = ACPI_METHOD_NEXT_ARGUMENT(Ptr); 248 } 249 break; 250 } 251 252 case ACPI_TYPE_LOCAL_REFERENCE: 253 { 254 Status = EvalConvertObjectReference(Ptr, Obj); 255 if (!NT_SUCCESS(Status)) 256 return Status; 257 break; 258 } 259 260 default: 261 { 262 DPRINT1("Unsupported element type %lu\n", Obj->Type); 263 return STATUS_UNSUCCESSFUL; 264 } 265 } 266 267 return STATUS_SUCCESS; 268 } 269 270 /** 271 * @brief Returns the number of sub-objects (elements) in a package. 272 */ 273 static 274 CODE_SEG("PAGE") 275 ULONG 276 EvalGetPackageCount( 277 _In_ PACPI_METHOD_ARGUMENT Package, 278 _In_ PACPI_METHOD_ARGUMENT PackageArgument, 279 _In_ ULONG DataLength) 280 { 281 ACPI_METHOD_ARGUMENT* Ptr; 282 ULONG TotalLength = 0, TotalCount = 0; 283 284 PAGED_CODE(); 285 286 /* Empty package */ 287 if (DataLength < ACPI_METHOD_ARGUMENT_LENGTH(0) || Package->Argument == 0) 288 return 0; 289 290 Ptr = PackageArgument; 291 while (TotalLength < DataLength) 292 { 293 TotalLength += ACPI_METHOD_ARGUMENT_LENGTH_FROM_ARGUMENT(Ptr); 294 TotalCount++; 295 296 Ptr = ACPI_METHOD_NEXT_ARGUMENT(Ptr); 297 } 298 299 return TotalCount; 300 } 301 302 /** 303 * @brief Performs translation from the supplied method argument into an ACPI_OBJECT structure. 304 */ 305 static 306 CODE_SEG("PAGE") 307 NTSTATUS 308 EvalConvertParameterObjects( 309 _Out_ ACPI_OBJECT* Arg, 310 _In_ ULONG Depth, 311 _In_ PACPI_METHOD_ARGUMENT Argument, 312 _In_ PIO_STACK_LOCATION IoStack, 313 _In_ ULONG Offset) 314 { 315 PAGED_CODE(); 316 317 if (Depth >= ACPI_MAX_PACKAGE_DEPTH) 318 { 319 ASSERT(FALSE); 320 return STATUS_UNSUCCESSFUL; 321 } 322 323 /* Validate that the method argument fits into the buffer */ 324 if (Depth > 0) 325 { 326 Offset += ACPI_METHOD_ARGUMENT_LENGTH_FROM_ARGUMENT(Argument); 327 328 if (!AcpiVerifyInBuffer(IoStack, Offset)) 329 { 330 DPRINT1("Argument buffer outside of argument bounds\n"); 331 return STATUS_ACPI_INVALID_ARGTYPE; 332 } 333 } 334 335 switch (Argument->Type) 336 { 337 case ACPI_METHOD_ARGUMENT_INTEGER: 338 { 339 Arg->Type = ACPI_TYPE_INTEGER; 340 Arg->Integer.Value = (ULONG64)Argument->Argument; 341 break; 342 } 343 344 case ACPI_METHOD_ARGUMENT_STRING: 345 { 346 /* 347 * FIXME: Add tests and remove this. 348 * We should either default to an empty string, or reject the IOCTL. 349 */ 350 ASSERT(Argument->DataLength >= sizeof(UCHAR)); 351 if (Argument->DataLength < sizeof(UCHAR)) 352 { 353 return STATUS_NOT_IMPLEMENTED; 354 } 355 356 Arg->Type = ACPI_TYPE_STRING; 357 Arg->String.Pointer = (PCHAR)&Argument->Data[0]; 358 Arg->String.Length = Argument->DataLength - sizeof(UCHAR); 359 break; 360 } 361 362 case ACPI_METHOD_ARGUMENT_BUFFER: 363 { 364 Arg->Type = ACPI_TYPE_BUFFER; 365 Arg->Buffer.Pointer = &Argument->Data[0]; 366 Arg->Buffer.Length = Argument->DataLength; 367 break; 368 } 369 370 case ACPI_METHOD_ARGUMENT_PACKAGE: 371 { 372 ULONG i, PackageSize; 373 NTSTATUS Status; 374 PACPI_METHOD_ARGUMENT PackageArgument; 375 376 Arg->Type = ACPI_TYPE_PACKAGE; 377 378 Arg->Package.Count = EvalGetPackageCount(Argument, 379 (PACPI_METHOD_ARGUMENT)Argument->Data, 380 Argument->DataLength); 381 /* Empty package, nothing more to convert */ 382 if (Arg->Package.Count == 0) 383 { 384 Arg->Package.Elements = NULL; 385 break; 386 } 387 388 Status = RtlULongMult(Arg->Package.Count, sizeof(*Arg), &PackageSize); 389 if (!NT_SUCCESS(Status)) 390 { 391 DPRINT1("Invalid package count 0x%lx\n", Arg->Package.Count); 392 return STATUS_ACPI_INCORRECT_ARGUMENT_COUNT; 393 } 394 395 Arg->Package.Elements = ExAllocatePoolUninitialized(NonPagedPool, 396 PackageSize, 397 TAG_ACPI_PACKAGE_LIST); 398 if (!Arg->Package.Elements) 399 return STATUS_INSUFFICIENT_RESOURCES; 400 401 PackageArgument = (PACPI_METHOD_ARGUMENT)Argument->Data; 402 for (i = 0; i < Arg->Package.Count; i++) 403 { 404 Status = EvalConvertParameterObjects(&Arg->Package.Elements[i], 405 Depth + 1, 406 PackageArgument, 407 IoStack, 408 Offset); 409 if (!NT_SUCCESS(Status)) 410 { 411 ExFreePoolWithTag(Arg->Package.Elements, TAG_ACPI_PACKAGE_LIST); 412 return Status; 413 } 414 415 PackageArgument = ACPI_METHOD_NEXT_ARGUMENT(PackageArgument); 416 } 417 break; 418 } 419 420 default: 421 { 422 DPRINT1("Unknown argument type %u\n", Argument->Type); 423 return STATUS_UNSUCCESSFUL; 424 } 425 } 426 427 return STATUS_SUCCESS; 428 } 429 430 /** 431 * @brief Creates a counted array of ACPI_OBJECTs from the given input buffer. 432 */ 433 static 434 CODE_SEG("PAGE") 435 NTSTATUS 436 EvalCreateParametersList( 437 _In_ PIRP Irp, 438 _In_ PIO_STACK_LOCATION IoStack, 439 _In_ PACPI_EVAL_INPUT_BUFFER EvalInputBuffer, 440 _Out_ ACPI_OBJECT_LIST* ParamList) 441 { 442 ACPI_OBJECT* Arg; 443 444 PAGED_CODE(); 445 446 if (!AcpiVerifyInBuffer(IoStack, RTL_SIZEOF_THROUGH_FIELD(ACPI_EVAL_INPUT_BUFFER, Signature))) 447 { 448 DPRINT1("Buffer too small\n"); 449 return STATUS_INFO_LENGTH_MISMATCH; 450 } 451 452 switch (EvalInputBuffer->Signature) 453 { 454 case ACPI_EVAL_INPUT_BUFFER_SIGNATURE: 455 { 456 if (!AcpiVerifyInBuffer(IoStack, sizeof(*EvalInputBuffer))) 457 { 458 DPRINT1("Buffer too small\n"); 459 return STATUS_INFO_LENGTH_MISMATCH; 460 } 461 462 ParamList->Count = 0; 463 break; 464 } 465 466 case ACPI_EVAL_INPUT_BUFFER_SIMPLE_INTEGER_SIGNATURE: 467 { 468 PACPI_EVAL_INPUT_BUFFER_SIMPLE_INTEGER SimpleInt; 469 470 if (!AcpiVerifyInBuffer(IoStack, sizeof(*SimpleInt))) 471 { 472 DPRINT1("Buffer too small\n"); 473 return STATUS_INFO_LENGTH_MISMATCH; 474 } 475 476 Arg = ExAllocatePoolUninitialized(NonPagedPool, sizeof(*Arg), TAG_ACPI_PARAMETERS_LIST); 477 if (!Arg) 478 return STATUS_INSUFFICIENT_RESOURCES; 479 480 ParamList->Count = 1; 481 ParamList->Pointer = Arg; 482 483 SimpleInt = Irp->AssociatedIrp.SystemBuffer; 484 485 Arg->Type = ACPI_TYPE_INTEGER; 486 Arg->Integer.Value = (ULONG64)SimpleInt->IntegerArgument; 487 break; 488 } 489 490 case ACPI_EVAL_INPUT_BUFFER_SIMPLE_STRING_SIGNATURE: 491 { 492 PACPI_EVAL_INPUT_BUFFER_SIMPLE_STRING SimpleStr; 493 494 if (!AcpiVerifyInBuffer(IoStack, sizeof(*SimpleStr))) 495 { 496 DPRINT1("Buffer too small\n"); 497 return STATUS_INFO_LENGTH_MISMATCH; 498 } 499 500 Arg = ExAllocatePoolUninitialized(NonPagedPool, sizeof(*Arg), TAG_ACPI_PARAMETERS_LIST); 501 if (!Arg) 502 return STATUS_INSUFFICIENT_RESOURCES; 503 504 ParamList->Count = 1; 505 ParamList->Pointer = Arg; 506 507 SimpleStr = Irp->AssociatedIrp.SystemBuffer; 508 509 Arg->Type = ACPI_TYPE_STRING; 510 Arg->String.Pointer = (PCHAR)SimpleStr->String; 511 Arg->String.Length = SimpleStr->StringLength; 512 break; 513 } 514 515 case ACPI_EVAL_INPUT_BUFFER_COMPLEX_SIGNATURE: 516 { 517 PACPI_EVAL_INPUT_BUFFER_COMPLEX ComplexBuffer; 518 PACPI_METHOD_ARGUMENT Argument; 519 ULONG i, Length, Offset, ArgumentsSize; 520 NTSTATUS Status; 521 522 if (!AcpiVerifyInBuffer(IoStack, sizeof(*ComplexBuffer))) 523 { 524 DPRINT1("Buffer too small\n"); 525 return STATUS_INFO_LENGTH_MISMATCH; 526 } 527 528 ComplexBuffer = Irp->AssociatedIrp.SystemBuffer; 529 530 ParamList->Count = ComplexBuffer->ArgumentCount; 531 if (ParamList->Count == 0) 532 { 533 DPRINT1("No arguments\n"); 534 return STATUS_ACPI_INCORRECT_ARGUMENT_COUNT; 535 } 536 537 Status = RtlULongMult(ParamList->Count, sizeof(*Arg), &ArgumentsSize); 538 if (!NT_SUCCESS(Status)) 539 { 540 DPRINT1("Invalid argument count 0x%lx\n", ParamList->Count); 541 return STATUS_ACPI_INCORRECT_ARGUMENT_COUNT; 542 } 543 544 Arg = ExAllocatePoolUninitialized(NonPagedPool, 545 ArgumentsSize, 546 TAG_ACPI_PARAMETERS_LIST); 547 if (!Arg) 548 return STATUS_INSUFFICIENT_RESOURCES; 549 550 ParamList->Pointer = Arg; 551 552 Argument = ComplexBuffer->Argument; 553 Length = FIELD_OFFSET(ACPI_EVAL_INPUT_BUFFER_COMPLEX, Argument); 554 555 for (i = 0; i < ParamList->Count; i++) 556 { 557 Offset = Length; 558 Length += ACPI_METHOD_ARGUMENT_LENGTH_FROM_ARGUMENT(Argument); 559 560 if (!AcpiVerifyInBuffer(IoStack, Length)) 561 { 562 DPRINT1("Argument buffer outside of argument bounds\n"); 563 564 ExFreePoolWithTag(ParamList->Pointer, TAG_ACPI_PARAMETERS_LIST); 565 return STATUS_ACPI_INVALID_ARGTYPE; 566 } 567 568 Status = EvalConvertParameterObjects(Arg, 0, Argument, IoStack, Offset); 569 if (!NT_SUCCESS(Status)) 570 { 571 ExFreePoolWithTag(ParamList->Pointer, TAG_ACPI_PARAMETERS_LIST); 572 return Status; 573 } 574 575 Arg++; 576 Argument = ACPI_METHOD_NEXT_ARGUMENT(Argument); 577 } 578 579 break; 580 } 581 582 default: 583 { 584 DPRINT1("Unsupported input buffer signature: 0x%lx\n", EvalInputBuffer->Signature); 585 return STATUS_INVALID_PARAMETER_1; 586 } 587 } 588 589 return STATUS_SUCCESS; 590 } 591 592 /** 593 * @brief Deallocates the memory for all sub-objects (elements) in a package. 594 */ 595 static 596 CODE_SEG("PAGE") 597 VOID 598 EvalFreeParameterArgument( 599 _In_ ACPI_OBJECT* Arg, 600 _In_ ULONG Depth) 601 { 602 ULONG i; 603 604 PAGED_CODE(); 605 606 if (Depth >= ACPI_MAX_PACKAGE_DEPTH) 607 { 608 ASSERT(FALSE); 609 return; 610 } 611 612 if (Arg->Type == ACPI_TYPE_PACKAGE) 613 { 614 for (i = 0; i < Arg->Package.Count; i++) 615 { 616 EvalFreeParameterArgument(&Arg->Package.Elements[i], Depth + 1); 617 } 618 619 /* Check if the package isn't empty, and free it */ 620 if (Arg->Package.Elements) 621 ExFreePoolWithTag(Arg->Package.Elements, TAG_ACPI_PACKAGE_LIST); 622 } 623 } 624 625 /** 626 * @brief Deallocates the given array of ACPI_OBJECTs. 627 */ 628 static 629 CODE_SEG("PAGE") 630 VOID 631 EvalFreeParametersList( 632 _In_ ACPI_OBJECT_LIST* ParamList) 633 { 634 ACPI_OBJECT* Arg; 635 ULONG i; 636 637 PAGED_CODE(); 638 639 Arg = ParamList->Pointer; 640 for (i = 0; i < ParamList->Count; i++) 641 { 642 EvalFreeParameterArgument(Arg++, 0); 643 } 644 645 ExFreePoolWithTag(ParamList->Pointer, TAG_ACPI_PARAMETERS_LIST); 646 } 647 648 /** 649 * @brief Converts the provided value of ACPI_STATUS to NTSTATUS return value. 650 */ 651 static 652 CODE_SEG("PAGE") 653 NTSTATUS 654 EvalAcpiStatusToNtStatus( 655 _In_ ACPI_STATUS AcpiStatus) 656 { 657 PAGED_CODE(); 658 659 if (ACPI_ENV_EXCEPTION(AcpiStatus)) 660 { 661 switch (AcpiStatus) 662 { 663 case AE_NOT_FOUND: 664 case AE_NOT_EXIST: 665 return STATUS_OBJECT_NAME_NOT_FOUND; 666 667 case AE_NO_MEMORY: 668 return STATUS_INSUFFICIENT_RESOURCES; 669 670 case AE_SUPPORT: 671 return STATUS_ACPI_INCORRECT_ARGUMENT_COUNT; 672 673 case AE_TIME: 674 return STATUS_IO_TIMEOUT; 675 676 case AE_NO_HARDWARE_RESPONSE: 677 return STATUS_IO_DEVICE_ERROR; 678 679 case AE_STACK_OVERFLOW: 680 return STATUS_ACPI_STACK_OVERFLOW; 681 682 default: 683 break; 684 } 685 } 686 687 if (ACPI_AML_EXCEPTION(AcpiStatus)) 688 { 689 switch (AcpiStatus) 690 { 691 case AE_AML_UNINITIALIZED_ARG: 692 return STATUS_ACPI_INCORRECT_ARGUMENT_COUNT; 693 694 default: 695 break; 696 } 697 } 698 699 return STATUS_UNSUCCESSFUL; 700 } 701 702 /** 703 * @brief Evaluates an ACPI namespace object. 704 */ 705 static 706 CODE_SEG("PAGE") 707 ACPI_STATUS 708 EvalEvaluateObject( 709 _In_ PPDO_DEVICE_DATA DeviceData, 710 _In_ PACPI_EVAL_INPUT_BUFFER EvalInputBuffer, 711 _In_ ACPI_OBJECT_LIST* ParamList, 712 _In_ ACPI_BUFFER* ReturnBuffer) 713 { 714 CHAR MethodName[ACPI_OBJECT_NAME_LENGTH]; 715 716 PAGED_CODE(); 717 718 RtlCopyMemory(MethodName, EvalInputBuffer->MethodName, ACPI_OBJECT_NAME_LENGTH); 719 MethodName[ACPI_OBJECT_NAME_LENGTH - 1] = ANSI_NULL; 720 721 return AcpiEvaluateObject(DeviceData->AcpiHandle, MethodName, ParamList, ReturnBuffer); 722 } 723 724 /** 725 * @brief Writes the results from the evaluation into the output IRP buffer. 726 */ 727 static 728 CODE_SEG("PAGE") 729 NTSTATUS 730 EvalCreateOutputArguments( 731 _In_ PIRP Irp, 732 _In_ PIO_STACK_LOCATION IoStack, 733 _In_ ACPI_BUFFER* ReturnBuffer) 734 { 735 ACPI_OBJECT* Obj; 736 ULONG ExtraParamLength, OutputBufSize; 737 PACPI_EVAL_OUTPUT_BUFFER OutputBuffer; 738 NTSTATUS Status; 739 ULONG Count; 740 741 PAGED_CODE(); 742 743 /* If we didn't get anything back then we're done */ 744 if (!ReturnBuffer->Pointer || ReturnBuffer->Length == 0) 745 return STATUS_SUCCESS; 746 747 /* No output buffer is provided, we're done */ 748 if (IoStack->Parameters.DeviceIoControl.OutputBufferLength == 0) 749 return STATUS_SUCCESS; 750 751 if (!AcpiVerifyOutBuffer(IoStack, sizeof(*OutputBuffer))) 752 { 753 DPRINT1("Buffer too small\n"); 754 755 return STATUS_BUFFER_TOO_SMALL; 756 } 757 758 Obj = ReturnBuffer->Pointer; 759 760 Status = EvalGetElementSize(Obj, 0, &Count, &ExtraParamLength); 761 if (!NT_SUCCESS(Status)) 762 return Status; 763 764 OutputBufSize = FIELD_OFFSET(ACPI_EVAL_OUTPUT_BUFFER, Argument) + ExtraParamLength; 765 766 #ifdef UNIT_TEST 767 OutputBuffer = Irp->OutputBuffer; 768 #else 769 OutputBuffer = Irp->AssociatedIrp.SystemBuffer; 770 #endif 771 OutputBuffer->Signature = ACPI_EVAL_OUTPUT_BUFFER_SIGNATURE; 772 OutputBuffer->Length = OutputBufSize; 773 OutputBuffer->Count = Count; 774 775 if (!AcpiVerifyOutBuffer(IoStack, OutputBufSize)) 776 { 777 DPRINT("Buffer too small (%lu/%lu)\n", 778 IoStack->Parameters.DeviceIoControl.OutputBufferLength, 779 OutputBufSize); 780 781 Irp->IoStatus.Information = OutputBufSize; 782 return STATUS_BUFFER_OVERFLOW; 783 } 784 785 Status = EvalConvertEvaluationResults(OutputBuffer->Argument, 0, Obj); 786 if (!NT_SUCCESS(Status)) 787 return Status; 788 789 Irp->IoStatus.Information = OutputBufSize; 790 return STATUS_SUCCESS; 791 } 792 793 CODE_SEG("PAGE") 794 NTSTATUS 795 NTAPI 796 Bus_PDO_EvalMethod( 797 _In_ PPDO_DEVICE_DATA DeviceData, 798 _Inout_ PIRP Irp) 799 { 800 PIO_STACK_LOCATION IoStack; 801 PACPI_EVAL_INPUT_BUFFER EvalInputBuffer; 802 ACPI_OBJECT_LIST ParamList; 803 ACPI_STATUS AcpiStatus; 804 NTSTATUS Status; 805 ACPI_BUFFER ReturnBuffer = { ACPI_ALLOCATE_BUFFER, NULL }; 806 807 PAGED_CODE(); 808 809 IoStack = IoGetCurrentIrpStackLocation(Irp); 810 EvalInputBuffer = Irp->AssociatedIrp.SystemBuffer; 811 812 Status = EvalCreateParametersList(Irp, IoStack, EvalInputBuffer, &ParamList); 813 if (!NT_SUCCESS(Status)) 814 return Status; 815 816 AcpiStatus = EvalEvaluateObject(DeviceData, EvalInputBuffer, &ParamList, &ReturnBuffer); 817 818 if (ParamList.Count != 0) 819 EvalFreeParametersList(&ParamList); 820 821 if (!ACPI_SUCCESS(AcpiStatus)) 822 { 823 DPRINT("Query method '%.4s' failed on %p with status 0x%04lx\n", 824 EvalInputBuffer->MethodName, 825 DeviceData->AcpiHandle, 826 AcpiStatus); 827 828 return EvalAcpiStatusToNtStatus(AcpiStatus); 829 } 830 831 Status = EvalCreateOutputArguments(Irp, IoStack, &ReturnBuffer); 832 833 if (ReturnBuffer.Pointer) 834 AcpiOsFree(ReturnBuffer.Pointer); 835 836 return Status; 837 } 838 839 #ifndef UNIT_TEST 840 CODE_SEG("PAGE") 841 VOID 842 NTAPI 843 Bus_PDO_EvalMethodWorker( 844 _In_ PVOID Parameter) 845 { 846 PEVAL_WORKITEM_DATA WorkItemData = Parameter; 847 NTSTATUS Status; 848 PIRP Irp; 849 850 PAGED_CODE(); 851 852 Irp = WorkItemData->Irp; 853 854 Status = Bus_PDO_EvalMethod(WorkItemData->DeviceData, Irp); 855 856 ExFreePoolWithTag(WorkItemData, 'ipcA'); 857 858 Irp->IoStatus.Status = Status; 859 IoCompleteRequest(Irp, IO_NO_INCREMENT); 860 } 861 #endif /* UNIT_TEST */ 862