1 /*
2  * PROJECT:     ReactOS API Tests
3  * LICENSE:     LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4  * PURPOSE:     Unit Tests for acpi!Bus_PDO_EvalMethod (IOCTL_ACPI_EVAL_METHOD handler)
5  * COPYRIGHT:   Copyright 2024 Dmitry Borisov (di.sean@protonmail.com)
6  */
7 
8 /* INCLUDES *******************************************************************/
9 
10 #include <apitest.h>
11 
12 #define WIN32_NO_STATUS
13 #include <ndk/rtlfuncs.h>
14 
15 #define UNIT_TEST
16 #include <acpi.h>
17 
18 #include <acpiioct.h>
19 #include <ntintsafe.h>
20 #include <initguid.h>
21 
22 /* TEST DEFINITIONS ***********************************************************/
23 
24 #define ok_eq_str_ex(entry, value, expected) \
25     ok(!strcmp(value, expected), \
26        "Line %lu: " #value " = \"%s\", expected \"%s\"\n", (entry)->Line, value, expected)
27 
28 #define ok_eq_print_ex(entry, value, expected, spec) \
29     ok((value) == (expected), \
30        "Line %lu: " #value " = " spec ", expected " spec "\n", (entry)->Line, value, expected)
31 
32 #define ok_not_print_ex(entry, value, expected, spec) \
33     ok((value) != (expected), \
34        "Line %lu: " #value " = " spec ", expected " spec "\n", (entry)->Line, value, expected)
35 
36 #define ok_eq_hex_ex(entry, value, expected)       ok_eq_print_ex(entry, value, expected, "0x%08lx")
37 #define ok_eq_pointer_ex(entry, value, expected)   ok_eq_print_ex(entry, value, expected, "%p")
38 #define ok_eq_int_ex(entry, value, expected)       ok_eq_print_ex(entry, value, expected, "%d")
39 #define ok_eq_uint_ex(entry, value, expected)      ok_eq_print_ex(entry, value, expected, "%u")
40 #define ok_eq_ulong_ex(entry, value, expected)     ok_eq_print_ex(entry, value, expected, "%lu")
41 #define ok_eq_ulonglong_ex(entry, value, expected) ok_eq_print_ex(entry, value, expected, "%I64u")
42 
43 #define ok_not_pointer_ex(entry, value, expected)  ok_not_print_ex(entry, value, expected, "%p")
44 
45 typedef struct _EVAL_TEST_ENTRY
46 {
47     ULONG Line;
48 
49     ULONG Flags;
50 #define STM_TEST_FLAG_INVALID_ARG_3_1              (1 << 0 )
51 #define STM_TEST_FLAG_INVALID_ARG_3_2              (1 << 1 )
52 #define STM_TEST_FLAG_INVALID_ARG_3_4              (1 << 2 )
53 #define STM_TEST_FLAG_INVALID_ARG_3_5              (1 << 3 )
54 #define STM_TEST_FLAG_INVALID_SIZE_1               (1 << 4 )
55 #define STM_TEST_FLAG_LARGE_ARG_BUFFER             (1 << 5 )
56 #define STM_TEST_FLAG_CHANGE_ARG_COUNT             (1 << 6 )
57 #define STM_TEST_FLAG_SUB_IN_BUFFER                (1 << 7 )
58 #define STM_TEST_FLAG_SUB_IRP_BUFFER               (1 << 8 )
59 #define STM_TEST_FLAG_SET_IN_BUFFER                (1 << 9 )
60 #define STM_TEST_FLAG_SET_IRP_BUFFER               (1 << 10)
61 #define STM_TEST_FLAG_BAD_ARG_TYPE                 (1 << 11)
62 
63 #define GTM_TEST_FLAG_BAD_SIGNARUTE                (1 << 0)
64 #define GTM_TEST_FLAG_BUFFER_HAS_SIGNARUTE         (1 << 1)
65 #define GTM_TEST_FLAG_BUFFER_HAS_COUNT             (1 << 2)
66 #define GTM_TEST_FLAG_BUFFER_HAS_LENGTH            (1 << 3)
67 #define GTM_TEST_FLAG_ARG_HAS_BUFFER_TYPE          (1 << 4)
68 #define GTM_TEST_FLAG_ARG_HAS_DATA_LENGTH          (1 << 5)
69 #define GTM_TEST_FLAG_INC_OUT_BUFFER               (1 << 6)
70 #define GTM_TEST_FLAG_DEC_OUT_BUFFER               (1 << 7)
71 #define GTM_TEST_FLAG_SET_OUT_BUFFER               (1 << 8)
72 
73 #define GTM_TEST_FLAG_METHOD_SUCCESS \
74     (GTM_TEST_FLAG_BUFFER_HAS_SIGNARUTE | \
75      GTM_TEST_FLAG_BUFFER_HAS_COUNT | GTM_TEST_FLAG_BUFFER_HAS_LENGTH | \
76      GTM_TEST_FLAG_ARG_HAS_BUFFER_TYPE | GTM_TEST_FLAG_ARG_HAS_DATA_LENGTH)
77 
78 #define DSM_TEST_FLAG_EMPTY_PACKAGE                (1 << 0)
79 #define DSM_TEST_FLAG_LARGE_SUB_PACKAGE_BUFFER     (1 << 1)
80 
81     NTSTATUS Status;
82     ULONG Value;
83 } EVAL_TEST_ENTRY;
84 
85 /* KERNEL DEFINITIONS (MOCK) **************************************************/
86 
87 #define PAGED_CODE()
88 #define CODE_SEG(...)
89 #define DPRINT(...)  do { if (0) DbgPrint(__VA_ARGS__); } while (0)
90 #define DPRINT1(...) do { if (0) DbgPrint(__VA_ARGS__); } while (0)
91 
92 typedef struct _IO_STACK_LOCATION
93 {
94     union
95     {
96         struct
97         {
98             ULONG OutputBufferLength;
99             ULONG InputBufferLength;
100         } DeviceIoControl;
101     } Parameters;
102 } IO_STACK_LOCATION, *PIO_STACK_LOCATION;
103 
104 typedef struct _IRP
105 {
106     union
107     {
108         PVOID SystemBuffer;
109     } AssociatedIrp;
110     IO_STATUS_BLOCK IoStatus;
111 
112     PVOID OutputBuffer;
113     IO_STACK_LOCATION MyStack;
114 } IRP, *PIRP;
115 
116 static LONG DrvpBlocksAllocated = 0;
117 
118 #define ExAllocatePoolUninitialized ExAllocatePoolWithTag
119 #define NonPagedPool 1
120 static
121 PVOID
122 ExAllocatePoolWithTag(ULONG PoolType, SIZE_T NumberOfBytes, ULONG Tag)
123 {
124     PULONG_PTR Mem;
125 
126     Mem = HeapAlloc(GetProcessHeap(), 0, NumberOfBytes + 2 * sizeof(PVOID));
127     Mem[0] = NumberOfBytes;
128     Mem[1] = Tag;
129 
130     ++DrvpBlocksAllocated;
131 
132     return (PVOID)(Mem + 2);
133 }
134 
135 static
136 VOID
137 ExFreePoolWithTag(PVOID MemPtr, ULONG Tag)
138 {
139     PULONG_PTR Mem = MemPtr;
140 
141     Mem -= 2;
142     ok(Mem[1] == Tag, "Tag is %lx, expected %lx\n", Tag, Mem[1]);
143     HeapFree(GetProcessHeap(), 0, Mem);
144 
145     --DrvpBlocksAllocated;
146 }
147 
148 static
149 PIO_STACK_LOCATION
150 IoGetCurrentIrpStackLocation(PIRP Irp)
151 {
152     return &Irp->MyStack;
153 }
154 
155 /* ACPI DEFINITIONS ***********************************************************/
156 
157 #include <pshpack1.h>
158 typedef struct _IDE_ACPI_TIMING_MODE_BLOCK
159 {
160     struct
161     {
162         ULONG PioSpeed;
163         ULONG DmaSpeed;
164     } Drive[2];
165 
166     ULONG ModeFlags;
167 } IDE_ACPI_TIMING_MODE_BLOCK, *PIDE_ACPI_TIMING_MODE_BLOCK;
168 #include <poppack.h>
169 
170 #define STM_ID_BLOCK_SIZE    512
171 
172 /* ACPI DEFINITIONS (MOCK) ****************************************************/
173 
174 #define FAKE_SB_NAMESPACE_ACPI_HANDLE    0xFF0F0001
175 #define FAKE_INTB_ACPI_HANDLE            0xFF0F0002
176 #define FAKE_INTC_ACPI_HANDLE            0xFF0F0003
177 
178 typedef struct _PDO_DEVICE_DATA
179 {
180     HANDLE AcpiHandle;
181 } PDO_DEVICE_DATA, *PPDO_DEVICE_DATA;
182 
183 typedef struct _GTM_OBJECT_BUFFER
184 {
185     ACPI_OBJECT Obj;
186     IDE_ACPI_TIMING_MODE_BLOCK TimingMode;
187 } GTM_OBJECT_BUFFER, *PGTM_OBJECT_BUFFER;
188 
189 typedef struct _BIF_OBJECT_BUFFER
190 {
191     ACPI_OBJECT Obj;
192     ACPI_OBJECT BatteryInformation[13];
193     CHAR Buffer1[1 + 1];
194     CHAR Buffer2[1 + 1];
195     CHAR Buffer3[4 + 1];
196     CHAR Buffer4[7 + 1];
197 } BIF_OBJECT_BUFFER, *PBIF_OBJECT_BUFFER;
198 
199 typedef struct _PCL_OBJECT_BUFFER
200 {
201     ACPI_OBJECT Obj;
202 } PCL_OBJECT_BUFFER, *PPCL_OBJECT_BUFFER;
203 
204 typedef struct _PRT_OBJECT_BUFFER
205 {
206     ACPI_OBJECT Obj;
207     ACPI_OBJECT PackageContainer[2];
208     ACPI_OBJECT Package1[4];
209     ACPI_OBJECT Package2[4];
210 } PRT_OBJECT_BUFFER, *PPRT_OBJECT_BUFFER;
211 
212 DEFINE_GUID(MY_DSM_GUID,
213             0xB76E0B40, 0x3EC6, 0x4DBD, 0x8A, 0xCB, 0x8B, 0xCA, 0x65, 0xB8, 0xBC, 0x70);
214 
215 static const ULONG DrvpBifIntegerFields[9] =
216 {
217     0, 50000, 50000, 1, 10000, 100, 50, 1, 1
218 };
219 
220 static const ULONG DrvpMyDsmIntegerFields[3] =
221 {
222     0xAAAAAAAA, 0xBBBBBBBB, 0xDDDDDDDD
223 };
224 
225 static const EVAL_TEST_ENTRY* DrvpEvalTestEntry;
226 
227 void *
228 AcpiOsAllocate (
229     ACPI_SIZE               Size)
230 {
231     return ExAllocatePoolWithTag(NonPagedPool, Size, 'FFUB');
232 }
233 
234 void
235 AcpiOsFree (
236     void *                  Memory)
237 {
238     ExFreePoolWithTag(Memory, 'FFUB');
239 }
240 
241 ACPI_STATUS
242 AcpiGetName (
243     ACPI_HANDLE             Handle,
244     UINT32                  NameType,
245     ACPI_BUFFER             *Buffer)
246 {
247     /* We don't support anything else */
248     ok(NameType == ACPI_SINGLE_NAME, "Unexpected call to %s\n", __FUNCTION__);
249 
250     /* Return a NULL-terminated string */
251     if (Buffer->Length < (4 + 1))
252         return AE_BUFFER_OVERFLOW;
253 
254     switch ((ULONG_PTR)Handle)
255     {
256         case FAKE_SB_NAMESPACE_ACPI_HANDLE:
257             RtlCopyMemory(Buffer->Pointer, "_SB_", sizeof("_SB_"));
258             break;
259 
260         case FAKE_INTB_ACPI_HANDLE:
261             RtlCopyMemory(Buffer->Pointer, "LNKB", sizeof("LNKB"));
262             break;
263 
264         case FAKE_INTC_ACPI_HANDLE:
265             RtlCopyMemory(Buffer->Pointer, "LNKC", sizeof("LNKC"));
266             break;
267 
268         default:
269             return AE_BAD_PARAMETER;
270     }
271 
272     return AE_OK;
273 }
274 
275 ACPI_STATUS
276 AcpiEvaluateObject (
277     ACPI_HANDLE             Object,
278     ACPI_STRING             Pathname,
279     ACPI_OBJECT_LIST        *ParameterObjects,
280     ACPI_BUFFER             *ReturnObjectBuffer)
281 {
282     UNREFERENCED_PARAMETER(Object);
283 
284     /* We don't support anything else */
285     ok(ReturnObjectBuffer->Length == ACPI_ALLOCATE_BUFFER,
286        "Unexpected call to %s\n", __FUNCTION__);
287 
288     if (strcmp(Pathname, "_STM") == 0)
289     {
290         ACPI_OBJECT* Arg;
291         PIDE_ACPI_TIMING_MODE_BLOCK TimingMode;
292 
293         if (ParameterObjects->Count > 3)
294             return AE_AML_UNINITIALIZED_ARG;
295 
296         if (ParameterObjects->Count != 3)
297             return AE_OK;
298 
299         /* Argument 1 */
300         {
301             Arg = ParameterObjects->Pointer;
302 
303             ok_eq_uint_ex(DrvpEvalTestEntry, Arg->Type, ACPI_TYPE_BUFFER);
304             ok_eq_uint_ex(DrvpEvalTestEntry, Arg->Buffer.Length, sizeof(*TimingMode));
305 
306             TimingMode = (PIDE_ACPI_TIMING_MODE_BLOCK)Arg->Buffer.Pointer;
307 
308             ok_eq_ulong_ex(DrvpEvalTestEntry, TimingMode->Drive[0].PioSpeed, 508LU);
309             ok_eq_ulong_ex(DrvpEvalTestEntry, TimingMode->Drive[0].DmaSpeed, 120LU);
310             ok_eq_ulong_ex(DrvpEvalTestEntry, TimingMode->Drive[1].PioSpeed, 240LU);
311             ok_eq_ulong_ex(DrvpEvalTestEntry, TimingMode->Drive[1].DmaSpeed, 180LU);
312             ok_eq_hex_ex(DrvpEvalTestEntry, TimingMode->ModeFlags, 0x10LU);
313         }
314         /* Argument 2 */
315         {
316             ++Arg;
317 
318             ok_eq_uint_ex(DrvpEvalTestEntry, Arg->Type, ACPI_TYPE_BUFFER);
319             ok_eq_uint_ex(DrvpEvalTestEntry, Arg->Buffer.Length, STM_ID_BLOCK_SIZE);
320         }
321         /* Argument 3 */
322         {
323             ++Arg;
324 
325             ok_eq_uint_ex(DrvpEvalTestEntry, Arg->Type, ACPI_TYPE_BUFFER);
326             ok_eq_uint_ex(DrvpEvalTestEntry, Arg->Buffer.Length, STM_ID_BLOCK_SIZE);
327         }
328 
329         return AE_OK;
330     }
331     else if (strcmp(Pathname, "_GTM") == 0)
332     {
333         PGTM_OBJECT_BUFFER ReturnObject;
334         PIDE_ACPI_TIMING_MODE_BLOCK TimingMode;
335 
336         ReturnObject = AcpiOsAllocate(sizeof(*ReturnObject));
337         if (!ReturnObject)
338             return AE_NO_MEMORY;
339 
340         /*
341          * VPC 2007 output
342          * AcpiGetHandle(NULL, "\\_SB.PCI0.IDE0.CHN1", &ObjHandle);
343          * AcpiEvaluateObject(ObjHandle, "_GTM", NULL, &ReturnObj);
344          */
345         TimingMode = &ReturnObject->TimingMode;
346         TimingMode->Drive[0].PioSpeed = 900;
347         TimingMode->Drive[0].DmaSpeed = 900;
348         TimingMode->Drive[1].PioSpeed = 120;
349         TimingMode->Drive[1].DmaSpeed = 120;
350         TimingMode->ModeFlags = 0x12;
351 
352         ReturnObject->Obj.Type = ACPI_TYPE_BUFFER;
353         ReturnObject->Obj.Buffer.Length = sizeof(*TimingMode);
354         ReturnObject->Obj.Buffer.Pointer = (PUCHAR)TimingMode;
355 
356         ReturnObjectBuffer->Pointer = ReturnObject;
357         ReturnObjectBuffer->Length = sizeof(*ReturnObject);
358         return AE_OK;
359     }
360     else if (strcmp(Pathname, "_BIF") == 0)
361     {
362         PBIF_OBJECT_BUFFER ReturnObject;
363         ACPI_OBJECT* BatteryInformation;
364         ULONG i;
365 
366         ReturnObject = AcpiOsAllocate(sizeof(*ReturnObject));
367         if (!ReturnObject)
368             return AE_NO_MEMORY;
369 
370         /*
371          * Vbox 7.0 output
372          * AcpiGetHandle(NULL, "\\_SB.PCI0.BAT0", &ObjHandle);
373          * AcpiEvaluateObject(ObjHandle, "_BIF", NULL, &ReturnObj);
374          */
375         BatteryInformation = &ReturnObject->BatteryInformation[0];
376         for (i = 0; i < RTL_NUMBER_OF(DrvpBifIntegerFields); ++i)
377         {
378             BatteryInformation[i].Integer.Type = ACPI_TYPE_INTEGER;
379             BatteryInformation[i].Integer.Value = DrvpBifIntegerFields[i];
380         }
381         BatteryInformation[i].String.Type = ACPI_TYPE_STRING;
382         BatteryInformation[i].String.Length = 1; /* Excluding the trailing null */
383         BatteryInformation[i].String.Pointer = &ReturnObject->Buffer1[0];
384         RtlCopyMemory(BatteryInformation[i].String.Pointer, "1", sizeof("1"));
385         ++i;
386         BatteryInformation[i].String.Type = ACPI_TYPE_STRING;
387         BatteryInformation[i].String.Length = 1;
388         BatteryInformation[i].String.Pointer = &ReturnObject->Buffer2[0];
389         RtlCopyMemory(BatteryInformation[i].String.Pointer, "0", sizeof("0"));
390         ++i;
391         BatteryInformation[i].String.Type = ACPI_TYPE_STRING;
392         BatteryInformation[i].String.Length = 4;
393         BatteryInformation[i].String.Pointer = &ReturnObject->Buffer3[0];
394         RtlCopyMemory(BatteryInformation[i].String.Pointer, "VBOX", sizeof("VBOX"));
395         ++i;
396         BatteryInformation[i].String.Type = ACPI_TYPE_STRING;
397         BatteryInformation[i].String.Length = 7;
398         BatteryInformation[i].String.Pointer = &ReturnObject->Buffer4[0];
399         RtlCopyMemory(BatteryInformation[i].String.Pointer, "innotek", sizeof("innotek"));
400 
401         ReturnObject->Obj.Type = ACPI_TYPE_PACKAGE;
402         ReturnObject->Obj.Package.Count = 13;
403         ReturnObject->Obj.Package.Elements = BatteryInformation;
404 
405         ReturnObjectBuffer->Pointer = ReturnObject;
406         ReturnObjectBuffer->Length = sizeof(*ReturnObject);
407         return AE_OK;
408     }
409     else if (strcmp(Pathname, "_PCL") == 0)
410     {
411         PPCL_OBJECT_BUFFER ReturnObject;
412 
413         ReturnObject = AcpiOsAllocate(sizeof(*ReturnObject));
414         if (!ReturnObject)
415             return AE_NO_MEMORY;
416 
417         /*
418          * Vbox 7.0 output
419          * AcpiGetHandle(NULL, "\\_SB.PCI0.AC", &ObjHandle);
420          * AcpiEvaluateObject(ObjHandle, "_PCL", NULL, &ReturnObj);
421          */
422         ReturnObject->Obj.Reference.Type = ACPI_TYPE_LOCAL_REFERENCE;
423         ReturnObject->Obj.Reference.ActualType = ACPI_TYPE_DEVICE;
424         ReturnObject->Obj.Reference.Handle = (ACPI_HANDLE)(ULONG_PTR)FAKE_SB_NAMESPACE_ACPI_HANDLE;
425 
426         ReturnObjectBuffer->Pointer = ReturnObject;
427         ReturnObjectBuffer->Length = sizeof(*ReturnObject);
428         return AE_OK;
429     }
430     else if (strcmp(Pathname, "_PRT") == 0)
431     {
432         PPRT_OBJECT_BUFFER ReturnObject;
433         ULONG i;
434 
435         ReturnObject = AcpiOsAllocate(sizeof(*ReturnObject));
436         if (!ReturnObject)
437             return AE_NO_MEMORY;
438 
439         /*
440          * Vbox 7.0 output
441          * AcpiGetHandle(NULL, "\\_SB.PCI0", &ObjHandle);
442          * AcpiEvaluateObject(ObjHandle, "_PRT", NULL, &ReturnObj);
443          *
444          * NOTE: To avoid similar copies of code executed and tested over and over again
445          * we return 2 packages. The original method returns 120 packages.
446          */
447         ReturnObject->Obj.Type = ACPI_TYPE_PACKAGE;
448         ReturnObject->Obj.Package.Count = 2;
449         ReturnObject->Obj.Package.Elements = &ReturnObject->PackageContainer[0];
450 
451         i = 0;
452         ReturnObject->PackageContainer[i].Type = ACPI_TYPE_PACKAGE;
453         ReturnObject->PackageContainer[i].Package.Count = 4;
454         ReturnObject->PackageContainer[i].Package.Elements = &ReturnObject->Package1[0];
455         ++i;
456         ReturnObject->PackageContainer[i].Type = ACPI_TYPE_PACKAGE;
457         ReturnObject->PackageContainer[i].Package.Count = 4;
458         ReturnObject->PackageContainer[i].Package.Elements = &ReturnObject->Package2[0];
459 
460         /* Package 1 */
461         i = 0;
462         ReturnObject->Package1[i].Integer.Type = ACPI_TYPE_INTEGER;
463         ReturnObject->Package1[i].Integer.Value = 0x0002FFFF;
464         ++i;
465         ReturnObject->Package1[i].Integer.Type = ACPI_TYPE_INTEGER;
466         ReturnObject->Package1[i].Integer.Value = 0x00000000;
467         ++i;
468         ReturnObject->Package1[i].Reference.Type = ACPI_TYPE_LOCAL_REFERENCE;
469         ReturnObject->Package1[i].Reference.ActualType = ACPI_TYPE_DEVICE;
470         ReturnObject->Package1[i].Reference.Handle = (ACPI_HANDLE)(ULONG_PTR)FAKE_INTB_ACPI_HANDLE;
471         ++i;
472         ReturnObject->Package1[i].Integer.Type = ACPI_TYPE_INTEGER;
473         ReturnObject->Package1[i].Integer.Value = 0x00000000;
474 
475         /* Package 2 */
476         i = 0;
477         ReturnObject->Package2[i].Integer.Type = ACPI_TYPE_INTEGER;
478         ReturnObject->Package2[i].Integer.Value = 0x0002FFFF;
479         ++i;
480         ReturnObject->Package2[i].Integer.Type = ACPI_TYPE_INTEGER;
481         ReturnObject->Package2[i].Integer.Value = 0x00000001;
482         ++i;
483         ReturnObject->Package2[i].Reference.Type = ACPI_TYPE_LOCAL_REFERENCE;
484         ReturnObject->Package2[i].Reference.ActualType = ACPI_TYPE_DEVICE;
485         ReturnObject->Package2[i].Reference.Handle = (ACPI_HANDLE)(ULONG_PTR)FAKE_INTC_ACPI_HANDLE;
486         ++i;
487         ReturnObject->Package2[i].Integer.Type = ACPI_TYPE_INTEGER;
488         ReturnObject->Package2[i].Integer.Value = 0x00000000;
489 
490         ReturnObjectBuffer->Pointer = ReturnObject;
491         ReturnObjectBuffer->Length = sizeof(*ReturnObject);
492         return AE_OK;
493     }
494     else if (strcmp(Pathname, "_DSM") == 0)
495     {
496         ACPI_OBJECT* Arg;
497 
498         /* Assumed object count per the spec */
499         ok_eq_uint(ParameterObjects->Count, 4);
500 
501         if (ParameterObjects->Count != 4)
502             return AE_AML_UNINITIALIZED_ARG;
503 
504         /* Argument 1 */
505         {
506             Arg = ParameterObjects->Pointer;
507 
508             ok_eq_uint_ex(DrvpEvalTestEntry, Arg->Type, ACPI_TYPE_BUFFER);
509             ok_eq_uint_ex(DrvpEvalTestEntry, Arg->Buffer.Length, sizeof(GUID));
510         }
511 
512         /* NOTE: This UUID doesn't exist, for testing purposes only */
513         if (IsEqualGUID(Arg->Buffer.Pointer, &MY_DSM_GUID))
514         {
515             /* Argument 2 */
516             {
517                 ++Arg;
518 
519                 ok_eq_uint_ex(DrvpEvalTestEntry, Arg->Type, ACPI_TYPE_INTEGER);
520                 ok_eq_ulonglong_ex(DrvpEvalTestEntry, Arg->Integer.Value, 1ULL);
521             }
522             /* Argument 3 */
523             {
524                 ++Arg;
525 
526                 ok_eq_uint_ex(DrvpEvalTestEntry, Arg->Type, ACPI_TYPE_INTEGER);
527                 ok_eq_ulonglong_ex(DrvpEvalTestEntry, Arg->Integer.Value, 2ULL);
528             }
529             /* Argument 4 */
530             {
531                 ++Arg;
532 
533                 ok_eq_uint_ex(DrvpEvalTestEntry, Arg->Type, ACPI_TYPE_PACKAGE);
534 
535                 if (DrvpEvalTestEntry->Flags & DSM_TEST_FLAG_EMPTY_PACKAGE)
536                 {
537                     ok_eq_uint_ex(DrvpEvalTestEntry, Arg->Package.Count, 0);
538                     ok_eq_pointer_ex(DrvpEvalTestEntry, Arg->Package.Elements, NULL);
539                 }
540                 else
541                 {
542                     ACPI_OBJECT* PackageArg;
543                     ACPI_OBJECT* PackageArg2;
544                     ULONG i;
545 
546                     ok_eq_uint_ex(DrvpEvalTestEntry, Arg->Package.Count, 4);
547                     ok_not_pointer_ex(DrvpEvalTestEntry, Arg->Package.Elements, NULL);
548 
549                     if (!Arg->Package.Elements)
550                         return AE_AML_UNINITIALIZED_ARG;
551 
552                     /* Package 1 Arguments 1-2 */
553                     PackageArg = Arg->Package.Elements;
554                     for (i = 0; i < RTL_NUMBER_OF(DrvpMyDsmIntegerFields) - 1; i++)
555                     {
556                         ok_eq_uint_ex(DrvpEvalTestEntry, PackageArg->Type, ACPI_TYPE_INTEGER);
557                         ok_eq_ulonglong_ex(DrvpEvalTestEntry,
558                                            PackageArg->Integer.Value,
559                                            (ULONG64)DrvpMyDsmIntegerFields[i]);
560 
561                         ++PackageArg;
562                     }
563 
564                     /* Package 1 Argument 3 */
565                     {
566                         Arg = PackageArg;
567 
568                         ok_eq_uint_ex(DrvpEvalTestEntry, Arg->Type, ACPI_TYPE_PACKAGE);
569                         ok_eq_uint_ex(DrvpEvalTestEntry, Arg->Package.Count, 1);
570 
571                         /* Package 2 Argument 1 */
572                         PackageArg2 = Arg->Package.Elements;
573 
574                         ok_eq_uint_ex(DrvpEvalTestEntry, PackageArg2->Type, ACPI_TYPE_STRING);
575 
576                         /* Excluding the trailing null */
577                         ok_eq_uint_ex(DrvpEvalTestEntry,
578                                       PackageArg2->String.Length,
579                                       (sizeof("1_TESTDATATESTDATA_2") - 1));
580                         ok_eq_int_ex(DrvpEvalTestEntry,
581                                      memcmp(PackageArg2->String.Pointer,
582                                             "1_TESTDATATESTDATA_2",
583                                             sizeof("1_TESTDATATESTDATA_2") - 1),
584                                      0);
585                     }
586                     /* Package 1 Argument 4 */
587                     {
588                         ++PackageArg;
589 
590                         ok_eq_uint_ex(DrvpEvalTestEntry, PackageArg->Type, ACPI_TYPE_INTEGER);
591                         ok_eq_ulonglong_ex(DrvpEvalTestEntry,
592                                            PackageArg->Integer.Value,
593                                            (ULONG64)DrvpMyDsmIntegerFields[2]);
594                     }
595                 }
596             }
597 
598             return AE_OK;
599         }
600     }
601 
602     return AE_NOT_FOUND;
603 }
604 
605 #include "../../../../drivers/bus/acpi/eval.c"
606 
607 /* GLOBALS ********************************************************************/
608 
609 /* 2 ID blocks + timings + room for the test data */
610 #define STM_MAX_BUFFER_SIZE \
611     (FIELD_OFFSET(ACPI_EVAL_INPUT_BUFFER_COMPLEX, Argument) + \
612      2 * STM_ID_BLOCK_SIZE + sizeof(IDE_ACPI_TIMING_MODE_BLOCK) + 0x100)
613 
614 #define GTM_MAX_BUFFER_SIZE \
615     (FIELD_OFFSET(ACPI_EVAL_OUTPUT_BUFFER, Argument) + \
616      ACPI_METHOD_ARGUMENT_LENGTH(sizeof(IDE_ACPI_TIMING_MODE_BLOCK)) + 0x50)
617 
618 static const EVAL_TEST_ENTRY DrvpSmtTests[] =
619 {
620     { __LINE__, 0, STATUS_SUCCESS },
621     { __LINE__, STM_TEST_FLAG_INVALID_SIZE_1, STATUS_ACPI_INVALID_ARGTYPE },
622     { __LINE__, STM_TEST_FLAG_LARGE_ARG_BUFFER, STATUS_ACPI_INVALID_ARGTYPE },
623     { __LINE__, STM_TEST_FLAG_SUB_IN_BUFFER, STATUS_SUCCESS, 1 },
624     { __LINE__, STM_TEST_FLAG_SUB_IN_BUFFER, STATUS_SUCCESS, 9 },
625     { __LINE__, STM_TEST_FLAG_SUB_IRP_BUFFER, STATUS_SUCCESS, 1 },
626     { __LINE__, STM_TEST_FLAG_SUB_IRP_BUFFER, STATUS_SUCCESS, 9 },
627     { __LINE__, STM_TEST_FLAG_SET_IN_BUFFER, STATUS_SUCCESS, 0 },
628     { __LINE__, STM_TEST_FLAG_SET_IRP_BUFFER, STATUS_INFO_LENGTH_MISMATCH, 0 },
629     { __LINE__, STM_TEST_FLAG_SET_IRP_BUFFER, STATUS_INFO_LENGTH_MISMATCH,
630                 RTL_SIZEOF_THROUGH_FIELD(ACPI_EVAL_INPUT_BUFFER, Signature) - 2 },
631     { __LINE__, STM_TEST_FLAG_SET_IRP_BUFFER, STATUS_INFO_LENGTH_MISMATCH,
632                 RTL_SIZEOF_THROUGH_FIELD(ACPI_EVAL_INPUT_BUFFER, Signature) - 1 },
633     { __LINE__, STM_TEST_FLAG_SET_IRP_BUFFER, STATUS_INFO_LENGTH_MISMATCH,
634                 RTL_SIZEOF_THROUGH_FIELD(ACPI_EVAL_INPUT_BUFFER, Signature)  },
635     { __LINE__, STM_TEST_FLAG_SET_IRP_BUFFER, STATUS_INFO_LENGTH_MISMATCH,
636                 sizeof(ACPI_EVAL_INPUT_BUFFER) - 2 },
637     { __LINE__, STM_TEST_FLAG_SET_IRP_BUFFER, STATUS_INFO_LENGTH_MISMATCH,
638                 sizeof(ACPI_EVAL_INPUT_BUFFER) - 1 },
639     { __LINE__, STM_TEST_FLAG_SET_IRP_BUFFER, STATUS_INSUFFICIENT_RESOURCES,
640                 sizeof(ACPI_EVAL_INPUT_BUFFER) },
641     { __LINE__, STM_TEST_FLAG_SET_IRP_BUFFER, STATUS_INSUFFICIENT_RESOURCES,
642                 sizeof(ACPI_EVAL_INPUT_BUFFER) + 1 },
643     { __LINE__, STM_TEST_FLAG_SET_IRP_BUFFER, STATUS_INSUFFICIENT_RESOURCES,
644                 sizeof(ACPI_EVAL_INPUT_BUFFER) + 2 },
645     { __LINE__, STM_TEST_FLAG_BAD_ARG_TYPE, STATUS_SUCCESS, 0 },
646     { __LINE__, STM_TEST_FLAG_CHANGE_ARG_COUNT, STATUS_ACPI_INCORRECT_ARGUMENT_COUNT, 0 },
647 
648 #if 0
649     /*
650      * The return status depends on AML interpreter implementation
651      * and testing it is not practical, keeping this for reference only.
652      */
653     { __LINE__, STM_TEST_FLAG_INVALID_ARG_3_1, STATUS_SUCCESS },
654     { __LINE__, STM_TEST_FLAG_INVALID_ARG_3_2, STATUS_ACPI_INVALID_ARGTYPE },
655     { __LINE__, STM_TEST_FLAG_INVALID_ARG_3_4, STATUS_SUCCESS },
656     { __LINE__, STM_TEST_FLAG_INVALID_ARG_3_5, STATUS_SUCCESS },
657     { __LINE__, STM_TEST_FLAG_CHANGE_ARG_COUNT, STATUS_ACPI_INCORRECT_ARGUMENT_COUNT, 30 },
658     { __LINE__, STM_TEST_FLAG_CHANGE_ARG_COUNT, STATUS_ACPI_INCORRECT_ARGUMENT_COUNT, 2 },
659 #endif
660 };
661 
662 static const EVAL_TEST_ENTRY DrvpGtmTests[] =
663 {
664     { __LINE__, GTM_TEST_FLAG_METHOD_SUCCESS, STATUS_SUCCESS },
665     { __LINE__, GTM_TEST_FLAG_METHOD_SUCCESS |
666                 GTM_TEST_FLAG_INC_OUT_BUFFER, STATUS_SUCCESS, 1 },
667     { __LINE__, GTM_TEST_FLAG_METHOD_SUCCESS |
668                 GTM_TEST_FLAG_DEC_OUT_BUFFER, STATUS_BUFFER_OVERFLOW, 1 },
669     { __LINE__, GTM_TEST_FLAG_SET_OUT_BUFFER, STATUS_SUCCESS, 0 },
670     { __LINE__, GTM_TEST_FLAG_SET_OUT_BUFFER, STATUS_BUFFER_TOO_SMALL, 1 },
671     { __LINE__, GTM_TEST_FLAG_SET_OUT_BUFFER, STATUS_BUFFER_TOO_SMALL,
672                 FIELD_OFFSET(ACPI_EVAL_OUTPUT_BUFFER, Argument) - 1 },
673     { __LINE__, GTM_TEST_FLAG_SET_OUT_BUFFER, STATUS_BUFFER_TOO_SMALL,
674                 FIELD_OFFSET(ACPI_EVAL_OUTPUT_BUFFER, Argument) },
675     { __LINE__, GTM_TEST_FLAG_SET_OUT_BUFFER, STATUS_BUFFER_TOO_SMALL,
676                 FIELD_OFFSET(ACPI_EVAL_OUTPUT_BUFFER, Argument) + 1 },
677     { __LINE__, GTM_TEST_FLAG_SET_OUT_BUFFER, STATUS_BUFFER_TOO_SMALL,
678                 sizeof(ACPI_EVAL_OUTPUT_BUFFER) - 1 },
679     { __LINE__, GTM_TEST_FLAG_BUFFER_HAS_SIGNARUTE |
680                 GTM_TEST_FLAG_BUFFER_HAS_COUNT |
681                 GTM_TEST_FLAG_BUFFER_HAS_LENGTH |
682                 GTM_TEST_FLAG_SET_OUT_BUFFER,
683                 STATUS_BUFFER_OVERFLOW,
684                 sizeof(ACPI_EVAL_OUTPUT_BUFFER) },
685     { __LINE__, GTM_TEST_FLAG_BUFFER_HAS_SIGNARUTE |
686                 GTM_TEST_FLAG_BUFFER_HAS_COUNT |
687                 GTM_TEST_FLAG_BUFFER_HAS_LENGTH |
688                 GTM_TEST_FLAG_SET_OUT_BUFFER,
689                 STATUS_BUFFER_OVERFLOW,
690                 sizeof(ACPI_EVAL_OUTPUT_BUFFER) + 1 },
691 
692     /* Pass an invalid signature */
693     { __LINE__, GTM_TEST_FLAG_BAD_SIGNARUTE, STATUS_INVALID_PARAMETER_1 },
694     { __LINE__, GTM_TEST_FLAG_BAD_SIGNARUTE | GTM_TEST_FLAG_SET_OUT_BUFFER,
695                 STATUS_INVALID_PARAMETER_1, 0 },
696     { __LINE__, GTM_TEST_FLAG_BAD_SIGNARUTE | GTM_TEST_FLAG_SET_OUT_BUFFER,
697                 STATUS_BUFFER_TOO_SMALL,
698                 sizeof(ACPI_EVAL_OUTPUT_BUFFER) - 1 },
699     { __LINE__, GTM_TEST_FLAG_BAD_SIGNARUTE | GTM_TEST_FLAG_SET_OUT_BUFFER,
700                 STATUS_INVALID_PARAMETER_1,
701                 sizeof(ACPI_EVAL_OUTPUT_BUFFER) },
702 };
703 
704 static const EVAL_TEST_ENTRY DrvpBifTests[] =
705 {
706     { __LINE__, 0, STATUS_SUCCESS },
707 };
708 
709 static const EVAL_TEST_ENTRY DrvpPclTests[] =
710 {
711     { __LINE__, 0, STATUS_SUCCESS },
712 };
713 
714 static const EVAL_TEST_ENTRY DrvpPrtTests[] =
715 {
716     { __LINE__, 0, STATUS_SUCCESS },
717 };
718 
719 static const EVAL_TEST_ENTRY DrvpDsmTests[] =
720 {
721     { __LINE__, 0, STATUS_SUCCESS },
722     { __LINE__, DSM_TEST_FLAG_EMPTY_PACKAGE, STATUS_SUCCESS },
723     { __LINE__, DSM_TEST_FLAG_LARGE_SUB_PACKAGE_BUFFER, STATUS_ACPI_INVALID_ARGTYPE },
724 };
725 
726 /* FUNCTIONS ******************************************************************/
727 
728 static
729 NTSTATUS
730 DrvCallAcpiDriver(
731     _In_ PVOID InputBuffer,
732     _In_ ULONG InputBufferLength,
733     _Out_opt_ PACPI_EVAL_OUTPUT_BUFFER OutputBuffer,
734     _In_ ULONG OutputBufferLength)
735 {
736     PDO_DEVICE_DATA DeviceData;
737     IRP Irp;
738 
739     DeviceData.AcpiHandle = NULL;
740 
741     Irp.AssociatedIrp.SystemBuffer = InputBuffer;
742     Irp.OutputBuffer = OutputBuffer;
743 
744     Irp.MyStack.Parameters.DeviceIoControl.InputBufferLength = InputBufferLength;
745     Irp.MyStack.Parameters.DeviceIoControl.OutputBufferLength = OutputBufferLength;
746 
747     return Bus_PDO_EvalMethod(&DeviceData, &Irp);
748 }
749 
750 static
751 VOID
752 DrvEvaluateStmObject(
753     _In_ const EVAL_TEST_ENTRY* TestEntry,
754     _In_ PIDE_ACPI_TIMING_MODE_BLOCK TimingMode,
755     _In_ PUCHAR IdBlock,
756     _In_ PACPI_EVAL_INPUT_BUFFER_COMPLEX InputBuffer)
757 {
758     PACPI_METHOD_ARGUMENT Argument, Argument2, Argument3;
759     NTSTATUS Status;
760     ULONG InputBufferSize, IrpBufferSize;
761 
762     InputBufferSize = FIELD_OFFSET(ACPI_EVAL_INPUT_BUFFER_COMPLEX, Argument) +
763                       ACPI_METHOD_ARGUMENT_LENGTH(sizeof(*TimingMode)) +
764                       ACPI_METHOD_ARGUMENT_LENGTH(STM_ID_BLOCK_SIZE) +
765                       ACPI_METHOD_ARGUMENT_LENGTH(STM_ID_BLOCK_SIZE);
766 
767     if (TestEntry->Flags & STM_TEST_FLAG_INVALID_SIZE_1)
768     {
769         InputBufferSize -= ACPI_METHOD_ARGUMENT_LENGTH(STM_ID_BLOCK_SIZE) +
770                            ACPI_METHOD_ARGUMENT_LENGTH(STM_ID_BLOCK_SIZE);
771     }
772 
773     InputBuffer->MethodNameAsUlong = 'MTS_'; // _STM
774     InputBuffer->Signature = ACPI_EVAL_INPUT_BUFFER_COMPLEX_SIGNATURE;
775     if (TestEntry->Flags & STM_TEST_FLAG_SUB_IN_BUFFER)
776     {
777         InputBuffer->Size = InputBufferSize - TestEntry->Value;
778     }
779     else if (TestEntry->Flags & STM_TEST_FLAG_SET_IN_BUFFER)
780     {
781         InputBuffer->Size = TestEntry->Value;
782     }
783     else
784     {
785         InputBuffer->Size = InputBufferSize;
786     }
787 
788     if (TestEntry->Flags & STM_TEST_FLAG_CHANGE_ARG_COUNT)
789     {
790         InputBuffer->ArgumentCount = TestEntry->Value;
791     }
792     else
793     {
794         InputBuffer->ArgumentCount = 3;
795     }
796 
797     /* Argument 1: The channel timing information block */
798     Argument = InputBuffer->Argument;
799     ACPI_METHOD_SET_ARGUMENT_BUFFER(Argument, TimingMode, sizeof(*TimingMode));
800 
801     /* Argument 2: The ATA drive ID block */
802     Argument2 = ACPI_METHOD_NEXT_ARGUMENT(Argument);
803     ACPI_METHOD_SET_ARGUMENT_BUFFER(Argument2, IdBlock, STM_ID_BLOCK_SIZE);
804 
805     /* Argument 3: The ATA drive ID block */
806     Argument3 = ACPI_METHOD_NEXT_ARGUMENT(Argument2);
807     ACPI_METHOD_SET_ARGUMENT_BUFFER(Argument3, IdBlock, STM_ID_BLOCK_SIZE);
808 
809     if (TestEntry->Flags & STM_TEST_FLAG_BAD_ARG_TYPE)
810     {
811         Argument3->Type = 0xFFFF;
812     }
813 
814     if (TestEntry->Flags & STM_TEST_FLAG_LARGE_ARG_BUFFER)
815     {
816         Argument2->DataLength = STM_ID_BLOCK_SIZE * 2;
817         Argument3->DataLength = STM_ID_BLOCK_SIZE * 2;
818     }
819 
820     if (TestEntry->Flags & STM_TEST_FLAG_INVALID_ARG_3_1)
821     {
822         ACPI_METHOD_SET_ARGUMENT_STRING(Argument3, IdBlock);
823     }
824     else if (TestEntry->Flags & STM_TEST_FLAG_INVALID_ARG_3_2)
825     {
826         ACPI_METHOD_SET_ARGUMENT_INTEGER(Argument3, 0xDEADBEEF);
827     }
828     else if (TestEntry->Flags & STM_TEST_FLAG_INVALID_ARG_3_4)
829     {
830         Argument3->DataLength += 5;
831     }
832     else if (TestEntry->Flags & STM_TEST_FLAG_INVALID_ARG_3_5)
833     {
834         Argument3->DataLength -= 5;
835     }
836 
837     if (TestEntry->Flags & STM_TEST_FLAG_SUB_IRP_BUFFER)
838     {
839         IrpBufferSize = InputBufferSize - TestEntry->Value;
840     }
841     else if (TestEntry->Flags & STM_TEST_FLAG_SET_IRP_BUFFER)
842     {
843         IrpBufferSize = TestEntry->Value;
844     }
845     else
846     {
847         IrpBufferSize = InputBufferSize;
848     }
849 
850     /* Evaluate the _STM method */
851     DrvpEvalTestEntry = TestEntry;
852     Status = DrvCallAcpiDriver(InputBuffer, IrpBufferSize, NULL, 0);
853 
854     ok_eq_hex_ex(TestEntry, Status, TestEntry->Status);
855 }
856 
857 static
858 VOID
859 DrvTestComplexBuffer(VOID)
860 {
861     IDE_ACPI_TIMING_MODE_BLOCK TimingMode;
862     UCHAR IdBlock[STM_ID_BLOCK_SIZE];
863     ULONG i;
864     UCHAR Buffer[STM_MAX_BUFFER_SIZE];
865     PACPI_EVAL_INPUT_BUFFER_COMPLEX InputBuffer = (PACPI_EVAL_INPUT_BUFFER_COMPLEX)Buffer;
866 
867     /* Initialize method arguments */
868     RtlZeroMemory(IdBlock, sizeof(IdBlock));
869     TimingMode.Drive[0].PioSpeed = 508;
870     TimingMode.Drive[0].DmaSpeed = 120;
871     TimingMode.Drive[1].PioSpeed = 240;
872     TimingMode.Drive[1].DmaSpeed = 180;
873     TimingMode.ModeFlags = 0x10;
874 
875     for (i = 0; i < RTL_NUMBER_OF(DrvpSmtTests); ++i)
876     {
877         DrvEvaluateStmObject(&DrvpSmtTests[i], &TimingMode, IdBlock, InputBuffer);
878     }
879 }
880 
881 static
882 VOID
883 DrvEvaluateGtmObject(
884     _In_ const EVAL_TEST_ENTRY* TestEntry,
885     _In_ PACPI_EVAL_OUTPUT_BUFFER OutputBuffer)
886 {
887     ACPI_EVAL_INPUT_BUFFER InputBuffer;
888     ULONG OutputBufferSize;
889     NTSTATUS Status;
890     PACPI_METHOD_ARGUMENT Argument;
891     ULONG Signature, Count, Length;
892     USHORT Type, DataLength;
893     PIDE_ACPI_TIMING_MODE_BLOCK TimingMode;
894 
895     InputBuffer.MethodNameAsUlong = 'MTG_'; // _GTM
896     if (TestEntry->Flags & GTM_TEST_FLAG_BAD_SIGNARUTE)
897         InputBuffer.Signature = 'BAD0';
898     else
899         InputBuffer.Signature = ACPI_EVAL_INPUT_BUFFER_SIGNATURE;
900 
901     OutputBufferSize = FIELD_OFFSET(ACPI_EVAL_OUTPUT_BUFFER, Argument) +
902                        ACPI_METHOD_ARGUMENT_LENGTH(sizeof(*TimingMode));
903 
904     if (TestEntry->Flags & GTM_TEST_FLAG_INC_OUT_BUFFER)
905     {
906         OutputBufferSize += TestEntry->Value;
907     }
908     else if (TestEntry->Flags & GTM_TEST_FLAG_DEC_OUT_BUFFER)
909     {
910         OutputBufferSize -= TestEntry->Value;
911     }
912     else if (TestEntry->Flags & GTM_TEST_FLAG_SET_OUT_BUFFER)
913     {
914         OutputBufferSize = TestEntry->Value;
915     }
916 
917     /* Evaluate the _GTM method */
918     Status = DrvCallAcpiDriver(&InputBuffer, sizeof(InputBuffer), OutputBuffer, OutputBufferSize);
919 
920     ok_eq_hex_ex(TestEntry, Status, TestEntry->Status);
921 
922     if (TestEntry->Flags & GTM_TEST_FLAG_BUFFER_HAS_SIGNARUTE)
923         Signature = ACPI_EVAL_OUTPUT_BUFFER_SIGNATURE;
924     else
925         Signature = 0;
926     ok_eq_hex_ex(TestEntry, OutputBuffer->Signature, Signature);
927 
928     if (TestEntry->Flags & GTM_TEST_FLAG_BUFFER_HAS_COUNT)
929         Count = 1;
930     else
931         Count = 0;
932     ok_eq_ulong_ex(TestEntry, OutputBuffer->Count, Count);
933 
934     if (TestEntry->Flags & GTM_TEST_FLAG_BUFFER_HAS_LENGTH)
935     {
936         Length = FIELD_OFFSET(ACPI_EVAL_OUTPUT_BUFFER, Argument) +
937                  ACPI_METHOD_ARGUMENT_LENGTH(sizeof(*TimingMode));
938     }
939     else
940     {
941         Length = 0;
942     }
943     ok_eq_ulong_ex(TestEntry, OutputBuffer->Length, Length);
944 
945     Argument = OutputBuffer->Argument;
946     if (TestEntry->Flags & GTM_TEST_FLAG_ARG_HAS_BUFFER_TYPE)
947         Type = ACPI_METHOD_ARGUMENT_BUFFER;
948     else
949         Type = ACPI_METHOD_ARGUMENT_INTEGER;
950     ok_eq_uint_ex(TestEntry, Argument->Type, Type);
951 
952     if (TestEntry->Flags & GTM_TEST_FLAG_ARG_HAS_DATA_LENGTH)
953         DataLength = sizeof(ACPI_EVAL_OUTPUT_BUFFER);
954     else
955         DataLength = 0;
956     ok_eq_uint_ex(TestEntry, Argument->DataLength, DataLength);
957 
958     if ((TestEntry->Flags & GTM_TEST_FLAG_ARG_HAS_BUFFER_TYPE) && NT_SUCCESS(TestEntry->Status))
959     {
960         TimingMode = (PIDE_ACPI_TIMING_MODE_BLOCK)Argument->Data;
961 
962         ok_eq_ulong_ex(TestEntry, TimingMode->Drive[0].PioSpeed, 900LU);
963         ok_eq_ulong_ex(TestEntry, TimingMode->Drive[0].DmaSpeed, 900LU);
964         ok_eq_ulong_ex(TestEntry, TimingMode->Drive[1].PioSpeed, 120LU);
965         ok_eq_ulong_ex(TestEntry, TimingMode->Drive[1].DmaSpeed, 120LU);
966         ok_eq_hex_ex(TestEntry, TimingMode->ModeFlags, 0x12LU);
967     }
968 }
969 
970 static
971 VOID
972 DrvTestInputBuffer(VOID)
973 {
974     UCHAR Buffer[GTM_MAX_BUFFER_SIZE];
975     ULONG i;
976     PACPI_EVAL_OUTPUT_BUFFER OutputBuffer = (PACPI_EVAL_OUTPUT_BUFFER)Buffer;
977 
978     for (i = 0; i < RTL_NUMBER_OF(DrvpGtmTests); ++i)
979     {
980         RtlZeroMemory(Buffer, sizeof(Buffer));
981 
982         DrvEvaluateGtmObject(&DrvpGtmTests[i], OutputBuffer);
983     }
984 }
985 
986 static
987 VOID
988 DrvEvaluateBifObject(
989     _In_ const EVAL_TEST_ENTRY* TestEntry,
990     _In_ PACPI_EVAL_OUTPUT_BUFFER OutputBuffer)
991 {
992     ACPI_EVAL_INPUT_BUFFER InputBuffer;
993     ULONG i, OutputBufferSize;
994     NTSTATUS Status;
995     PACPI_METHOD_ARGUMENT Argument;
996 
997     InputBuffer.MethodNameAsUlong = 'FIB_'; // _BIF
998     InputBuffer.Signature = ACPI_EVAL_INPUT_BUFFER_SIGNATURE;
999 
1000     OutputBufferSize = FIELD_OFFSET(ACPI_EVAL_OUTPUT_BUFFER, Argument) +
1001                        ACPI_METHOD_ARGUMENT_LENGTH(sizeof(ULONG)) * 9 +
1002                        ACPI_METHOD_ARGUMENT_LENGTH(sizeof("1")) +
1003                        ACPI_METHOD_ARGUMENT_LENGTH(sizeof("0")) +
1004                        ACPI_METHOD_ARGUMENT_LENGTH(sizeof("VBOX")) +
1005                        ACPI_METHOD_ARGUMENT_LENGTH(sizeof("innotek"));
1006 
1007     /* Evaluate the _BIF method */
1008     Status = DrvCallAcpiDriver(&InputBuffer, sizeof(InputBuffer), OutputBuffer, OutputBufferSize);
1009 
1010     ok_eq_hex_ex(TestEntry, Status, TestEntry->Status);
1011     ok_eq_hex_ex(TestEntry, OutputBuffer->Signature, (ULONG)ACPI_EVAL_OUTPUT_BUFFER_SIGNATURE);
1012     ok_eq_ulong_ex(TestEntry, OutputBuffer->Count, 13LU);
1013     ok_eq_ulong_ex(TestEntry, OutputBuffer->Length, OutputBufferSize);
1014 
1015     /* Arguments 1-9 */
1016     Argument = OutputBuffer->Argument;
1017     for (i = 0; i < RTL_NUMBER_OF(DrvpBifIntegerFields); ++i)
1018     {
1019         ok_eq_uint_ex(TestEntry, Argument->Type, ACPI_METHOD_ARGUMENT_INTEGER);
1020         ok_eq_uint_ex(TestEntry, Argument->DataLength, sizeof(ULONG));
1021         ok_eq_ulong_ex(TestEntry, Argument->Argument, DrvpBifIntegerFields[i]);
1022 
1023         Argument = ACPI_METHOD_NEXT_ARGUMENT(Argument);
1024     }
1025     /* Argument 10 */
1026     {
1027         ok_eq_uint_ex(TestEntry, Argument->Type, ACPI_METHOD_ARGUMENT_STRING);
1028         ok_eq_uint_ex(TestEntry, Argument->DataLength, sizeof("1")); // Including the trailing null
1029         ok_eq_str_ex(TestEntry, (PCSTR)Argument->Data, "1");
1030     }
1031     /* Argument 11 */
1032     {
1033         Argument = ACPI_METHOD_NEXT_ARGUMENT(Argument);
1034 
1035         ok_eq_uint_ex(TestEntry, Argument->Type, ACPI_METHOD_ARGUMENT_STRING);
1036         ok_eq_uint_ex(TestEntry, Argument->DataLength, sizeof("0"));
1037         ok_eq_str_ex(TestEntry, (PCSTR)Argument->Data, "0");
1038     }
1039     /* Argument 12 */
1040     {
1041         Argument = ACPI_METHOD_NEXT_ARGUMENT(Argument);
1042 
1043         ok_eq_uint_ex(TestEntry, Argument->Type, ACPI_METHOD_ARGUMENT_STRING);
1044         ok_eq_uint_ex(TestEntry, Argument->DataLength, sizeof("VBOX"));
1045         ok_eq_str_ex(TestEntry, (PCSTR)Argument->Data, "VBOX");
1046     }
1047     /* Argument 13 */
1048     {
1049         Argument = ACPI_METHOD_NEXT_ARGUMENT(Argument);
1050 
1051         ok_eq_uint_ex(TestEntry, Argument->Type, ACPI_METHOD_ARGUMENT_STRING);
1052         ok_eq_uint_ex(TestEntry, Argument->DataLength, sizeof("innotek"));
1053         ok_eq_str_ex(TestEntry, (PCSTR)Argument->Data, "innotek");
1054     }
1055 }
1056 
1057 static
1058 VOID
1059 DrvTestPackageReturnValueAndStringData(VOID)
1060 {
1061     UCHAR Buffer[0x100];
1062     ULONG i;
1063     PACPI_EVAL_OUTPUT_BUFFER OutputBuffer = (PACPI_EVAL_OUTPUT_BUFFER)Buffer;
1064 
1065     for (i = 0; i < RTL_NUMBER_OF(DrvpBifTests); ++i)
1066     {
1067         RtlZeroMemory(Buffer, sizeof(Buffer));
1068 
1069         DrvEvaluateBifObject(&DrvpBifTests[i], OutputBuffer);
1070     }
1071 }
1072 
1073 static
1074 VOID
1075 DrvEvaluatePclObject(
1076     _In_ const EVAL_TEST_ENTRY* TestEntry,
1077     _In_ PACPI_EVAL_OUTPUT_BUFFER OutputBuffer)
1078 {
1079     ACPI_EVAL_INPUT_BUFFER InputBuffer;
1080     ULONG OutputBufferSize;
1081     NTSTATUS Status;
1082     PACPI_METHOD_ARGUMENT Argument;
1083 
1084     InputBuffer.MethodNameAsUlong = 'LCP_'; // _PCL
1085     InputBuffer.Signature = ACPI_EVAL_INPUT_BUFFER_SIGNATURE;
1086 
1087     OutputBufferSize = FIELD_OFFSET(ACPI_EVAL_OUTPUT_BUFFER, Argument) +
1088                        ACPI_METHOD_ARGUMENT_LENGTH(sizeof("ABCD")); // ACPI name for the object
1089 
1090     /* Evaluate the _PCL method */
1091     Status = DrvCallAcpiDriver(&InputBuffer, sizeof(InputBuffer), OutputBuffer, OutputBufferSize);
1092 
1093     ok_eq_hex_ex(TestEntry, Status, TestEntry->Status);
1094     ok_eq_hex_ex(TestEntry, OutputBuffer->Signature, (ULONG)ACPI_EVAL_OUTPUT_BUFFER_SIGNATURE);
1095     ok_eq_ulong_ex(TestEntry, OutputBuffer->Count, 1LU);
1096     ok_eq_ulong_ex(TestEntry, OutputBuffer->Length, OutputBufferSize);
1097 
1098     Argument = OutputBuffer->Argument;
1099 
1100     ok_eq_uint_ex(TestEntry, Argument->Type, ACPI_METHOD_ARGUMENT_STRING);
1101     ok_eq_uint_ex(TestEntry, Argument->DataLength, sizeof("ABCD"));
1102     ok_eq_str_ex(TestEntry, (PCSTR)Argument->Data, "_SB_");
1103 }
1104 
1105 static
1106 VOID
1107 DrvTestReferenceReturnValue(VOID)
1108 {
1109     UCHAR Buffer[0x100];
1110     ULONG i;
1111     PACPI_EVAL_OUTPUT_BUFFER OutputBuffer = (PACPI_EVAL_OUTPUT_BUFFER)Buffer;
1112 
1113     for (i = 0; i < RTL_NUMBER_OF(DrvpPclTests); ++i)
1114     {
1115         RtlZeroMemory(Buffer, sizeof(Buffer));
1116 
1117         DrvEvaluatePclObject(&DrvpPclTests[i], OutputBuffer);
1118     }
1119 }
1120 
1121 static
1122 VOID
1123 DrvEvaluatePrtObject(
1124     _In_ const EVAL_TEST_ENTRY* TestEntry,
1125     _In_ PACPI_EVAL_OUTPUT_BUFFER OutputBuffer)
1126 {
1127     ACPI_EVAL_INPUT_BUFFER InputBuffer;
1128     ULONG PackageNum, ArgNum, OutputBufferSize;
1129     NTSTATUS Status;
1130     PACPI_METHOD_ARGUMENT Argument, PackageArgument;
1131 
1132     InputBuffer.MethodNameAsUlong = 'TRP_'; // _PRT
1133     InputBuffer.Signature = ACPI_EVAL_INPUT_BUFFER_SIGNATURE;
1134 
1135 #define PRT_PACKAGE_ENTRY_SIZE \
1136     (ACPI_METHOD_ARGUMENT_LENGTH(sizeof(ULONG)) * 3 + \
1137      ACPI_METHOD_ARGUMENT_LENGTH(sizeof("LNKB")))
1138 
1139     OutputBufferSize = FIELD_OFFSET(ACPI_EVAL_OUTPUT_BUFFER, Argument) +
1140                        ACPI_METHOD_ARGUMENT_LENGTH(PRT_PACKAGE_ENTRY_SIZE) * 2;
1141 
1142     /* Evaluate the _PRT method */
1143     Status = DrvCallAcpiDriver(&InputBuffer, sizeof(InputBuffer), OutputBuffer, OutputBufferSize);
1144 
1145     ok_eq_hex_ex(TestEntry, Status, TestEntry->Status);
1146     ok_eq_hex_ex(TestEntry, OutputBuffer->Signature, (ULONG)ACPI_EVAL_OUTPUT_BUFFER_SIGNATURE);
1147     ok_eq_ulong_ex(TestEntry, OutputBuffer->Count, 2LU);
1148     ok_eq_ulong_ex(TestEntry, OutputBuffer->Length, OutputBufferSize);
1149 
1150     Argument = OutputBuffer->Argument;
1151     for (PackageNum = 0; PackageNum < 2; PackageNum++)
1152     {
1153         ok_eq_uint_ex(TestEntry, Argument->Type, ACPI_METHOD_ARGUMENT_PACKAGE);
1154         ok_eq_uint_ex(TestEntry, Argument->DataLength, (USHORT)PRT_PACKAGE_ENTRY_SIZE);
1155 
1156         PackageArgument = (PACPI_METHOD_ARGUMENT)Argument->Data;
1157         for (ArgNum = 0; ArgNum < 4; ArgNum++)
1158         {
1159             if (ArgNum != 2)
1160             {
1161                 ULONG ExpectedValue;
1162 
1163                 ok_eq_uint_ex(TestEntry, PackageArgument->Type, ACPI_METHOD_ARGUMENT_INTEGER);
1164                 ok_eq_uint_ex(TestEntry, PackageArgument->DataLength, sizeof(ULONG));
1165 
1166                 if (ArgNum == 0)
1167                 {
1168                     ExpectedValue = 0x0002FFFF;
1169                 }
1170                 else
1171                 {
1172                     if ((PackageNum == 1) && (ArgNum == 1))
1173                         ExpectedValue = 0x00000001;
1174                     else
1175                         ExpectedValue = 0x00000000;
1176                 }
1177                 ok_eq_ulong_ex(TestEntry, PackageArgument->Argument, ExpectedValue);
1178             }
1179             else
1180             {
1181                 ok_eq_uint_ex(TestEntry, PackageArgument->Type, ACPI_METHOD_ARGUMENT_STRING);
1182                 ok_eq_uint_ex(TestEntry, PackageArgument->DataLength, sizeof("ABCD"));
1183                 ok_eq_str_ex(TestEntry, (PCSTR)PackageArgument->Data,
1184                              (PackageNum == 0) ? "LNKB" : "LNKC");
1185             }
1186 
1187             PackageArgument = ACPI_METHOD_NEXT_ARGUMENT(PackageArgument);
1188         }
1189 
1190         Argument = ACPI_METHOD_NEXT_ARGUMENT(Argument);
1191     }
1192 }
1193 
1194 static
1195 VOID
1196 DrvTestNestedPackageReturnValue(VOID)
1197 {
1198     UCHAR Buffer[0x100];
1199     ULONG i;
1200     PACPI_EVAL_OUTPUT_BUFFER OutputBuffer = (PACPI_EVAL_OUTPUT_BUFFER)Buffer;
1201 
1202     for (i = 0; i < RTL_NUMBER_OF(DrvpPclTests); ++i)
1203     {
1204         RtlZeroMemory(Buffer, sizeof(Buffer));
1205 
1206         DrvEvaluatePrtObject(&DrvpPrtTests[i], OutputBuffer);
1207     }
1208 }
1209 
1210 static
1211 VOID
1212 DrvEvaluateDsmObject(
1213     _In_ const EVAL_TEST_ENTRY* TestEntry)
1214 {
1215 #define MY_DSM_SUB_PACKAGE_ENTRY_SIZE \
1216     (ACPI_METHOD_ARGUMENT_LENGTH(sizeof("1_TESTDATATESTDATA_2")))
1217 
1218 #define MY_DSM_PACKAGE_ENTRY_SIZE \
1219     (ACPI_METHOD_ARGUMENT_LENGTH(sizeof(ULONG)) * 3 + \
1220      ACPI_METHOD_ARGUMENT_LENGTH(MY_DSM_SUB_PACKAGE_ENTRY_SIZE))
1221 
1222 #define MY_DSM_BUFFER_SIZE \
1223     (FIELD_OFFSET(ACPI_EVAL_INPUT_BUFFER_COMPLEX, Argument) + \
1224      ACPI_METHOD_ARGUMENT_LENGTH(sizeof(GUID)) + \
1225      ACPI_METHOD_ARGUMENT_LENGTH(sizeof(ULONG)) + \
1226      ACPI_METHOD_ARGUMENT_LENGTH(sizeof(ULONG)) + \
1227      ACPI_METHOD_ARGUMENT_LENGTH(MY_DSM_PACKAGE_ENTRY_SIZE))
1228 
1229     UCHAR Buffer[MY_DSM_BUFFER_SIZE];
1230     ULONG InputSize;
1231     NTSTATUS Status;
1232     PACPI_METHOD_ARGUMENT Argument, PackageArgument, PackageArgument2;
1233     PACPI_EVAL_INPUT_BUFFER_COMPLEX InputBuffer = (PACPI_EVAL_INPUT_BUFFER_COMPLEX)Buffer;
1234 
1235     RtlZeroMemory(Buffer, sizeof(Buffer));
1236 
1237     InputSize = MY_DSM_BUFFER_SIZE;
1238     if (TestEntry->Flags & DSM_TEST_FLAG_EMPTY_PACKAGE)
1239     {
1240         InputSize -= ACPI_METHOD_ARGUMENT_LENGTH(MY_DSM_PACKAGE_ENTRY_SIZE);
1241         InputSize += ACPI_METHOD_ARGUMENT_LENGTH(ACPI_METHOD_ARGUMENT_LENGTH(0));
1242     }
1243 
1244     InputBuffer->MethodNameAsUlong = 'MSD_'; // _DSM
1245     InputBuffer->Signature = ACPI_EVAL_INPUT_BUFFER_COMPLEX_SIGNATURE;
1246     InputBuffer->ArgumentCount = 4;
1247     InputBuffer->Size = InputSize;
1248 
1249     /* Argument 1: The UUID */
1250     Argument = InputBuffer->Argument;
1251     ACPI_METHOD_SET_ARGUMENT_BUFFER(Argument, &MY_DSM_GUID, sizeof(GUID));
1252 
1253     /* Argument 2: The Revision ID */
1254     Argument = ACPI_METHOD_NEXT_ARGUMENT(Argument);
1255     ACPI_METHOD_SET_ARGUMENT_INTEGER(Argument, 1);
1256 
1257     /* Argument 3: The Function Index */
1258     Argument = ACPI_METHOD_NEXT_ARGUMENT(Argument);
1259     ACPI_METHOD_SET_ARGUMENT_INTEGER(Argument, 2);
1260 
1261     /* Argument 4: The device-specific package */
1262     Argument = ACPI_METHOD_NEXT_ARGUMENT(Argument);
1263     Argument->Type = ACPI_METHOD_ARGUMENT_PACKAGE;
1264     if (TestEntry->Flags & DSM_TEST_FLAG_EMPTY_PACKAGE)
1265     {
1266         /* Empty package */
1267         Argument->DataLength = ACPI_METHOD_ARGUMENT_LENGTH(0);
1268         Argument->Argument = 0;
1269     }
1270     else
1271     {
1272         Argument->DataLength = MY_DSM_PACKAGE_ENTRY_SIZE;
1273 
1274         /* Package 1 Argument 1: Some test data */
1275         PackageArgument = (PACPI_METHOD_ARGUMENT)Argument->Data;
1276         ACPI_METHOD_SET_ARGUMENT_INTEGER(PackageArgument, DrvpMyDsmIntegerFields[0]);
1277 
1278         /* Package 1 Argument 2: Some test data */
1279         PackageArgument = ACPI_METHOD_NEXT_ARGUMENT(PackageArgument);
1280         ACPI_METHOD_SET_ARGUMENT_INTEGER(PackageArgument, DrvpMyDsmIntegerFields[1]);
1281 
1282         /* Package 1 Argument 3: Start a new subpackage */
1283         PackageArgument = ACPI_METHOD_NEXT_ARGUMENT(PackageArgument);
1284         PackageArgument->Type = ACPI_METHOD_ARGUMENT_PACKAGE;
1285         PackageArgument->DataLength = MY_DSM_SUB_PACKAGE_ENTRY_SIZE;
1286 
1287         /* Package 2 Argument 1: Some test data */
1288         PackageArgument2 = (PACPI_METHOD_ARGUMENT)PackageArgument->Data;
1289         ACPI_METHOD_SET_ARGUMENT_STRING(PackageArgument2, "1_TESTDATATESTDATA_2");
1290 
1291         if (TestEntry->Flags & DSM_TEST_FLAG_LARGE_SUB_PACKAGE_BUFFER)
1292         {
1293             PackageArgument2->DataLength = 32768;
1294         }
1295         else
1296         {
1297             /* Package 1 Argument 4: Some test data */
1298             PackageArgument = ACPI_METHOD_NEXT_ARGUMENT(PackageArgument);
1299             ACPI_METHOD_SET_ARGUMENT_INTEGER(PackageArgument, DrvpMyDsmIntegerFields[2]);
1300         }
1301     }
1302 
1303     /* Evaluate the _DSM method */
1304     DrvpEvalTestEntry = TestEntry;
1305     Status = DrvCallAcpiDriver(InputBuffer, InputSize, NULL, 0);
1306 
1307     ok_eq_hex_ex(TestEntry, Status, TestEntry->Status);
1308 }
1309 
1310 static
1311 VOID
1312 DrvTestPackageInputValue(VOID)
1313 {
1314     ULONG i;
1315 
1316     for (i = 0; i < RTL_NUMBER_OF(DrvpDsmTests); ++i)
1317     {
1318         DrvEvaluateDsmObject(&DrvpDsmTests[i]);
1319     }
1320 }
1321 
1322 static
1323 VOID
1324 DrvTestUnknownMethod(VOID)
1325 {
1326     NTSTATUS Status;
1327     ACPI_EVAL_INPUT_BUFFER InputBuffer;
1328 
1329     InputBuffer.MethodNameAsUlong = 'FFF_'; // _FFF
1330     InputBuffer.Signature = ACPI_EVAL_INPUT_BUFFER_SIGNATURE;
1331 
1332     /* Try to evaluate some unsupported control method */
1333     Status = DrvCallAcpiDriver(&InputBuffer, sizeof(InputBuffer), NULL, 0);
1334 
1335     ok_eq_hex(Status, STATUS_OBJECT_NAME_NOT_FOUND);
1336 }
1337 
1338 START_TEST(Bus_PDO_EvalMethod)
1339 {
1340     DrvTestComplexBuffer();
1341     DrvTestInputBuffer();
1342     DrvTestPackageReturnValueAndStringData();
1343     DrvTestReferenceReturnValue();
1344     DrvTestNestedPackageReturnValue();
1345     DrvTestPackageInputValue();
1346     DrvTestUnknownMethod();
1347 
1348     ok(DrvpBlocksAllocated == 0, "Leaking memory %ld blocks\n", DrvpBlocksAllocated);
1349 }
1350