1 /*
2  * PROJECT:     ReactOS Kernel-Mode Tests
3  * LICENSE:     LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4  * PURPOSE:     Test for HalQuerySystemInformation
5  * COPYRIGHT:   Copyright 2020 Thomas Faber (thomas.faber@reactos.org)
6  */
7 
8 #include <kmt_test.h>
9 
10 #define NDEBUG
11 #include <debug.h>
12 
13 static HAL_AMLI_BAD_IO_ADDRESS_LIST ExpectedList[] =
14 {
15     { 0x0000, 0x10, 1, NULL },
16     { 0x0020, 0x02, 0, NULL },
17     { 0x0040, 0x04, 1, NULL },
18     { 0x0048, 0x04, 1, NULL },
19     { 0x0070, 0x02, 1, NULL },
20     { 0x0074, 0x03, 1, NULL },
21     { 0x0081, 0x03, 1, NULL },
22     { 0x0087, 0x01, 1, NULL },
23     { 0x0089, 0x01, 1, NULL },
24     { 0x008A, 0x02, 1, NULL },
25     { 0x008F, 0x01, 1, NULL },
26     { 0x0090, 0x02, 1, NULL },
27     { 0x0093, 0x02, 1, NULL },
28     { 0x0096, 0x02, 1, NULL },
29     { 0x00A0, 0x02, 0, NULL },
30     { 0x00C0, 0x20, 1, NULL },
31     { 0x04D0, 0x02, 0, NULL },
32     /* We obviously don't have the expected pointer. Just use a non-null value */
33     { 0x0CF8, 0x08, 1, (PVOID)1 },
34     { 0x0000, 0x00, 0, NULL },
35 };
36 
37 static
38 void
39 TestAMLIllegalIOPortAddresses(void)
40 {
41     NTSTATUS Status;
42     PHAL_AMLI_BAD_IO_ADDRESS_LIST AddressList;
43     ULONG AddressListLength;
44     ULONG ReturnedLength;
45 
46     /* Query required size and check that it's valid */
47     ReturnedLength = 0x55555555;
48     Status = HalQuerySystemInformation(HalQueryAMLIIllegalIOPortAddresses,
49                                        0,
50                                        NULL,
51                                        &ReturnedLength);
52     ok_eq_hex(Status, STATUS_INFO_LENGTH_MISMATCH);
53     ok(ReturnedLength % sizeof(*AddressList) == 0, "List size %lu is not a multiple of %Iu\n", ReturnedLength, sizeof(*AddressList));
54     if (skip(ReturnedLength > 0 && ReturnedLength < 0x10000000, "Invalid length\n"))
55     {
56         return;
57     }
58     AddressListLength = ReturnedLength;
59     AddressList = ExAllocatePoolWithTag(NonPagedPool,
60                                         AddressListLength,
61                                         'OImK');
62     if (skip(AddressList != NULL, "Failed to alloc %lu bytes\n", AddressListLength))
63     {
64         return;
65     }
66 
67     if (ReturnedLength != sizeof(*AddressList))
68     {
69         /* Try with space for exactly one entry and make sure we get
70          * the same return code
71          */
72         RtlFillMemory(AddressList, AddressListLength, 0x55);
73         ReturnedLength = 0x55555555;
74         Status = HalQuerySystemInformation(HalQueryAMLIIllegalIOPortAddresses,
75                                            sizeof(*AddressList),
76                                            AddressList,
77                                            &ReturnedLength);
78         ok_eq_hex(Status, STATUS_INFO_LENGTH_MISMATCH);
79         ok_eq_ulong(ReturnedLength, AddressListLength);
80         ok_eq_hex(AddressList[0].BadAddrBegin, 0x55555555UL);
81     }
82 
83     /* One byte less than required should still return no data */
84     RtlFillMemory(AddressList, AddressListLength, 0x55);
85     ReturnedLength = 0x55555555;
86     Status = HalQuerySystemInformation(HalQueryAMLIIllegalIOPortAddresses,
87                                        AddressListLength - 1,
88                                        AddressList,
89                                        &ReturnedLength);
90     ok_eq_hex(Status, STATUS_INFO_LENGTH_MISMATCH);
91     ok_eq_ulong(ReturnedLength, AddressListLength);
92     ok_eq_hex(AddressList[0].BadAddrBegin, 0x55555555UL);
93 
94     /* Specify required size */
95     RtlFillMemory(AddressList, AddressListLength, 0x55);
96     ReturnedLength = 0x55555555;
97     Status = HalQuerySystemInformation(HalQueryAMLIIllegalIOPortAddresses,
98                                        AddressListLength,
99                                        AddressList,
100                                        &ReturnedLength);
101     ok_eq_hex(Status, STATUS_SUCCESS);
102     ok_eq_ulong(ReturnedLength, AddressListLength);
103 
104     /* Validate the table against our expectations */
105     ok_eq_ulong(ReturnedLength, sizeof(ExpectedList));
106     for (ULONG i = 0;
107          i < min(ReturnedLength, sizeof(ExpectedList)) / sizeof(*AddressList);
108          i++)
109     {
110         ok(AddressList[i].BadAddrBegin == ExpectedList[i].BadAddrBegin,
111            "[%lu] BadAddrBegin 0x%lx, expected 0x%lx\n",
112            i, AddressList[i].BadAddrBegin, ExpectedList[i].BadAddrBegin);
113         ok(AddressList[i].BadAddrSize == ExpectedList[i].BadAddrSize,
114            "[%lu] BadAddrSize 0x%lx, expected 0x%lx\n",
115            i, AddressList[i].BadAddrSize, ExpectedList[i].BadAddrSize);
116         ok(AddressList[i].OSVersionTrigger == ExpectedList[i].OSVersionTrigger,
117            "[%lu] OSVersionTrigger 0x%lx, expected 0x%lx\n",
118            i, AddressList[i].OSVersionTrigger, ExpectedList[i].OSVersionTrigger);
119         if (ExpectedList[i].IOHandler != NULL)
120         {
121             ok(AddressList[i].IOHandler != NULL,
122                "[%lu] IOHandler = %p\n", i, AddressList[i].IOHandler);
123         }
124         else
125         {
126             ok(AddressList[i].IOHandler == NULL,
127                "[%lu] IOHandler = %p\n", i, AddressList[i].IOHandler);
128         }
129 
130         /* If we got an I/O handler, try to call it */
131         if (AddressList[i].IOHandler != NULL)
132         {
133             ULONG Data = 0x55555555;
134 
135             /* We don't want to break devices, so call it with an address
136              * outside of its range, and it should return failure
137              */
138             Status = AddressList[i].IOHandler(TRUE,
139                                               AddressList[i].BadAddrBegin - 1,
140                                               1,
141                                               &Data);
142             ok(Status == STATUS_UNSUCCESSFUL,
143                "[%lu] IOHandler returned 0x%lx\n", i, Status);
144             ok(Data == 0x55555555,
145                "[%lu] IOHandler returned Data 0x%lx\n", i, Data);
146         }
147     }
148     ExFreePoolWithTag(AddressList, 'OImK');
149 }
150 
151 START_TEST(HalSystemInfo)
152 {
153     TestAMLIllegalIOPortAddresses();
154 }
155