1 /*
2  * PROJECT:         ReactOS kernel-mode tests
3  * LICENSE:         GPLv2+ - See COPYING in the top level directory
4  * PURPOSE:         Kernel-Mode Test Suite for Device Queues
5  * PROGRAMMERS:     Pavel Batusov, Moscow State Technical University
6  *                  Denis Volhonsky, Moscow State Technical University
7  *                  Alexandra Safonova, Moscow State Technical University
8  */
9 
10 #include <kmt_test.h>
11 
12 #define NDEBUG
13 #include <debug.h>
14 
15 #define NUMBER 255
16 #define INSERT_COUNT 5
17 
Check_mem(void * a,int n,int size)18 int Check_mem(void* a, int n, int size)
19 {
20     int i;
21     for (i = 0; i < size; i++) {
22         if (*((unsigned char*)a + i) != n) {
23             return 0;
24         }
25     }
26     return 1;
27 }
28 
Test_Initialize()29 void Test_Initialize()
30 {
31     PKDEVICE_QUEUE testing_queue;
32     void* double_queue;
33 
34     trace("******* Testing KeInitializeDeviceQueue ************\n");
35     DPRINT1("\nStart test for KeInitializeDeviceQueue function\n");
36 
37     testing_queue = ExAllocatePool(NonPagedPool, sizeof(KDEVICE_QUEUE));
38 
39     testing_queue->Busy = TRUE;
40     testing_queue->Size = 0;
41 
42     KeInitializeDeviceQueue(testing_queue);
43 
44     /* Check for properly setting up fields */
45     ok(!testing_queue->Busy, "(Initialize testing) Test 1:\tExpected 'not busy' status\n");
46     DPRINT1("Test 1 completed\n");
47 
48     ok(testing_queue->Size == sizeof(KDEVICE_QUEUE), "(Initialize testing) Test 2:\tExpected another size for KDEVICE_QUEUE\n");
49     DPRINT1("Test 2 completed\n");
50 
51     ok(testing_queue->Type == DeviceQueueObject, "(Initialize testing) Test 3:\tExpected type == DeviceQueueObject\n");
52     DPRINT1("Test 3 completed\n");
53 
54     /* Make sure it does not write outside allocated buffer */
55     double_queue = ExAllocatePool(NonPagedPool, sizeof(KDEVICE_QUEUE) * 2);
56 
57     memset(double_queue, NUMBER, sizeof(KDEVICE_QUEUE) * 2);
58     KeInitializeDeviceQueue(double_queue);
59 
60     ok(Check_mem((void*)((char*)double_queue + sizeof(KDEVICE_QUEUE)), NUMBER, sizeof(KDEVICE_QUEUE)), "(Initialize testing) Test 4:\tFunction uses someone else's memory \n");
61     DPRINT1("Test 4 completed\n");
62 
63 //====================================================================
64 
65     ExFreePool(testing_queue);
66     ExFreePool(double_queue);
67 
68     DPRINT1("KeInitializeDeviceQueue test finished\n");
69 }
70 
Tests_Insert_And_Delete()71 void Tests_Insert_And_Delete()
72 {
73     ULONG i, j;
74     PKDEVICE_QUEUE testing_queue;
75     PKDEVICE_QUEUE_ENTRY element;
76     KIRQL OldIrql;
77     PKDEVICE_QUEUE_ENTRY* elem_array;
78     PKDEVICE_QUEUE_ENTRY return_value;
79     PLIST_ENTRY next;
80     ULONG key;
81 
82     trace("******* Testing KeInsertDeviceQueue **************** \n");
83     DPRINT1("\nStart KeInsertDeviceQueue test\n");
84 
85     testing_queue = ExAllocatePool(NonPagedPool, sizeof(KDEVICE_QUEUE));
86     KeInitializeDeviceQueue(testing_queue);
87 
88     element = ExAllocatePool(NonPagedPool, sizeof(KDEVICE_QUEUE_ENTRY));
89 
90     /* Raise to dispatch level */
91     KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
92 
93     KeInsertDeviceQueue(testing_queue, element);
94     ok(!element->Inserted, "Wrong 'Inserted' status\n");
95     DPRINT1("Test 1 completed\n");
96 
97     /* Fill the queue*/
98     elem_array = ExAllocatePool(NonPagedPool, sizeof(PKDEVICE_QUEUE_ENTRY) * INSERT_COUNT);
99 
100     DPRINT1("Arrow of tests starting\n");
101     for (i = 0; i < INSERT_COUNT; i++) {
102         elem_array[i] = ExAllocatePool(NonPagedPool, sizeof(KDEVICE_QUEUE_ENTRY));
103         elem_array[i]->Inserted = FALSE;
104         elem_array[i]->SortKey = i;
105         KeInsertDeviceQueue(testing_queue, elem_array[i]);
106         ok(elem_array[i]->Inserted, "Element was not inserted\n");
107     }
108     DPRINT1("Arrow of tests complete\n");
109 
110     ok(testing_queue->Size == sizeof(KDEVICE_QUEUE), "Wrong size of queue\n");
111 
112     /* Check how the queue was filled */
113     next = &testing_queue->DeviceListHead;
114 
115     DPRINT1("Bunch of tests starting\n");
116     for (i = 0; i < INSERT_COUNT; i++) {
117         next = next->Flink;
118         key = CONTAINING_RECORD(next, KDEVICE_QUEUE_ENTRY, DeviceListEntry)->SortKey;
119         ok(key == i, "Sort key was changed\n");
120     }
121     DPRINT1("Bunch of tests completed\n");
122 
123     trace("****************************************************\n\n");
124     DPRINT1("KeInsertDeviceQueue test finish\n");
125 
126     /* Test deletion */
127     trace("******* Testing KeRemoveDeviceQueue **************** \n");
128     DPRINT1("\nStart KeRemoveDeviceQueue test\n");
129 
130     DPRINT1("Start deleting elements from queue\n");
131     for (i = 0; i < INSERT_COUNT; i++) {
132         return_value = KeRemoveDeviceQueue(testing_queue);
133         ok(return_value == elem_array[i], "Returning element != head element\n");
134         ok(return_value->Inserted == FALSE, "Returning element is still in queue\n");
135         next = &testing_queue->DeviceListHead;
136         for (j = i + 1; j < INSERT_COUNT; j++) {
137             next = next->Flink;
138             ok(CONTAINING_RECORD(next, KDEVICE_QUEUE_ENTRY, DeviceListEntry)->SortKey == j, "Queue was damaged\n");
139         }
140     }
141     DPRINT1("Deleting finish. Queue must be empty\n");
142 
143     ok(KeRemoveDeviceQueue(testing_queue) == NULL, "Queue is not empty\n");
144     ok(testing_queue->Busy == FALSE, "Queue is busy\n");
145 
146     trace("****************************************************\n\n");
147     DPRINT1("Finish KeRemoveDeviceQueue test\n");
148 
149     trace("******* Testing KeRemoveEntryDeviceQueue *********** \n");
150     DPRINT1("\nStart KeRemoveEntryDeviceQueue test\n");
151 
152     DPRINT1("Filling queue\n");
153     for (i = 0; i < INSERT_COUNT; i++) {
154         elem_array[i]->SortKey = i;
155         elem_array[i]->Inserted = FALSE;
156         KeInsertDeviceQueue(testing_queue, elem_array[i]);
157     }
158 
159     /* Delete half of all elements in the queue */
160     DPRINT1("Deleting elements\n");
161     for (i = 0; i < INSERT_COUNT / 2; i++) {
162         ok(KeRemoveEntryDeviceQueue(testing_queue, elem_array[i * 2 + 1]), "Element is not deleted\n");
163     }
164 
165     /* Checking queue */
166     DPRINT1("Checking\n");
167     next = &testing_queue->DeviceListHead;
168     for (i = 0; i < INSERT_COUNT / 2 + 1; i++) {
169         ok(CONTAINING_RECORD(next, KDEVICE_QUEUE_ENTRY, DeviceListEntry)->SortKey == i * 2, "Queue was damaged\n");
170         next = next->Flink;
171     }
172 
173     /* Trying delete elements, which are not in this queue */
174     DPRINT1("Trying delete nonexistent elements\n");
175     for (i = 0; i < INSERT_COUNT / 2; i++) {
176         ok(!KeRemoveEntryDeviceQueue(testing_queue, elem_array[i * 2 + 1]), "Wrong remove operation\n");
177     }
178 
179     trace("****************************************************\n\n");
180     /* Freeing memory */
181     for (i = 0; i < INSERT_COUNT; i++) {
182         ExFreePool(elem_array[i]);
183     }
184 
185     /* Return back to previous IRQL */
186     KeLowerIrql(OldIrql);
187 
188     ExFreePool(testing_queue);
189     ExFreePool(element);
190 }
191 
START_TEST(KeDeviceQueue)192 START_TEST(KeDeviceQueue)
193 {
194     Test_Initialize();
195     Tests_Insert_And_Delete();
196 }
197 
198