1 /*
2  * PROJECT:         ReactOS kernel-mode tests
3  * LICENSE:         GPLv2+ - See COPYING in the top level directory
4  * PURPOSE:         Kernel-Mode Test Suite Asynchronous Procedure Call test
5  * PROGRAMMER:      Thomas Faber <thomas.faber@reactos.org>
6  */
7 
8 #include <kmt_test.h>
9 
10 static
11 _IRQL_requires_min_(PASSIVE_LEVEL)
12 _IRQL_requires_max_(DISPATCH_LEVEL)
13 BOOLEAN
14 (NTAPI
15 *pKeAreAllApcsDisabled)(VOID);
16 
17 static
18 _Acquires_lock_(_Global_critical_region_)
19 _IRQL_requires_max_(APC_LEVEL)
20 VOID
21 (NTAPI
22 *pKeEnterGuardedRegion)(VOID);
23 
24 static
25 _Releases_lock_(_Global_critical_region_)
26 _IRQL_requires_max_(APC_LEVEL)
27 VOID
28 (NTAPI
29 *pKeLeaveGuardedRegion)(VOID);
30 
31 #define CheckApcs(KernelApcsDisabled, SpecialApcsDisabled, AllApcsDisabled, Irql) do    \
32 {                                                                                       \
33     ok_eq_bool(KeAreApcsDisabled(), KernelApcsDisabled || SpecialApcsDisabled);         \
34     ok_eq_int(Thread->KernelApcDisable, KernelApcsDisabled);                            \
35     if (pKeAreAllApcsDisabled)                                                          \
36         ok_eq_bool(pKeAreAllApcsDisabled(), AllApcsDisabled);                           \
37     ok_eq_int(Thread->SpecialApcDisable, SpecialApcsDisabled);                          \
38     ok_irql(Irql);                                                                      \
39 } while (0)
40 
41 START_TEST(KeApc)
42 {
43     KIRQL Irql;
44     PKTHREAD Thread;
45 
46     pKeAreAllApcsDisabled = KmtGetSystemRoutineAddress(L"KeAreAllApcsDisabled");
47     pKeEnterGuardedRegion = KmtGetSystemRoutineAddress(L"KeEnterGuardedRegion");
48     pKeLeaveGuardedRegion = KmtGetSystemRoutineAddress(L"KeLeaveGuardedRegion");
49 
50     if (skip(pKeAreAllApcsDisabled != NULL, "KeAreAllApcsDisabled unavailable\n"))
51     {
52         /* We can live without this function here */
53     }
54 
55     Thread = KeGetCurrentThread();
56 
57     CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
58 
59     /* critical region */
60     KeEnterCriticalRegion();
61       CheckApcs(-1, 0, FALSE, PASSIVE_LEVEL);
62       KeEnterCriticalRegion();
63         CheckApcs(-2, 0, FALSE, PASSIVE_LEVEL);
64         KeEnterCriticalRegion();
65           CheckApcs(-3, 0, FALSE, PASSIVE_LEVEL);
66         KeLeaveCriticalRegion();
67         CheckApcs(-2, 0, FALSE, PASSIVE_LEVEL);
68       KeLeaveCriticalRegion();
69       CheckApcs(-1, 0, FALSE, PASSIVE_LEVEL);
70     KeLeaveCriticalRegion();
71     CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
72 
73     /* guarded region */
74     if (!skip(pKeEnterGuardedRegion &&
75               pKeLeaveGuardedRegion, "Guarded regions not available\n"))
76     {
77         pKeEnterGuardedRegion();
78           CheckApcs(0, -1, TRUE, PASSIVE_LEVEL);
79           pKeEnterGuardedRegion();
80             CheckApcs(0, -2, TRUE, PASSIVE_LEVEL);
81             pKeEnterGuardedRegion();
82               CheckApcs(0, -3, TRUE, PASSIVE_LEVEL);
83             pKeLeaveGuardedRegion();
84             CheckApcs(0, -2, TRUE, PASSIVE_LEVEL);
85           pKeLeaveGuardedRegion();
86           CheckApcs(0, -1, TRUE, PASSIVE_LEVEL);
87         pKeLeaveGuardedRegion();
88         CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
89 
90         /* mix them */
91         pKeEnterGuardedRegion();
92           CheckApcs(0, -1, TRUE, PASSIVE_LEVEL);
93           KeEnterCriticalRegion();
94             CheckApcs(-1, -1, TRUE, PASSIVE_LEVEL);
95           KeLeaveCriticalRegion();
96           CheckApcs(0, -1, TRUE, PASSIVE_LEVEL);
97         pKeLeaveGuardedRegion();
98         CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
99 
100         KeEnterCriticalRegion();
101           CheckApcs(-1, 0, FALSE, PASSIVE_LEVEL);
102           pKeEnterGuardedRegion();
103             CheckApcs(-1, -1, TRUE, PASSIVE_LEVEL);
104           pKeLeaveGuardedRegion();
105           CheckApcs(-1, 0, FALSE, PASSIVE_LEVEL);
106         KeLeaveCriticalRegion();
107         CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
108     }
109 
110     /* leave without entering */
111     if (!KmtIsCheckedBuild)
112     {
113         KeLeaveCriticalRegion();
114         CheckApcs(1, 0, FALSE, PASSIVE_LEVEL);
115         KeEnterCriticalRegion();
116         CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
117 
118         if (!skip(pKeEnterGuardedRegion &&
119                   pKeLeaveGuardedRegion, "Guarded regions not available\n"))
120         {
121             pKeLeaveGuardedRegion();
122             CheckApcs(0, 1, TRUE, PASSIVE_LEVEL);
123             pKeEnterGuardedRegion();
124             CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
125 
126             KeLeaveCriticalRegion();
127             CheckApcs(1, 0, FALSE, PASSIVE_LEVEL);
128             pKeLeaveGuardedRegion();
129             CheckApcs(1, 1, TRUE, PASSIVE_LEVEL);
130             KeEnterCriticalRegion();
131             CheckApcs(0, 1, TRUE, PASSIVE_LEVEL);
132             pKeEnterGuardedRegion();
133             CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
134         }
135     }
136 
137     /* manually disable APCs */
138     Thread->KernelApcDisable = -1;
139     CheckApcs(-1, 0, FALSE, PASSIVE_LEVEL);
140     Thread->SpecialApcDisable = -1;
141     CheckApcs(-1, -1, TRUE, PASSIVE_LEVEL);
142     Thread->KernelApcDisable = 0;
143     CheckApcs(0, -1, TRUE, PASSIVE_LEVEL);
144     Thread->SpecialApcDisable = 0;
145     CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
146 
147     /* raised irql - APC_LEVEL should disable APCs */
148     KeRaiseIrql(APC_LEVEL, &Irql);
149       CheckApcs(0, 0, TRUE, APC_LEVEL);
150     KeLowerIrql(Irql);
151     CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
152 
153     /* KeAre*ApcsDisabled are documented to work up to DISPATCH_LEVEL... */
154     KeRaiseIrql(DISPATCH_LEVEL, &Irql);
155       CheckApcs(0, 0, TRUE, DISPATCH_LEVEL);
156     KeLowerIrql(Irql);
157     CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
158 
159     /* ... but also work on higher levels! */
160     KeRaiseIrql(HIGH_LEVEL, &Irql);
161       CheckApcs(0, 0, TRUE, HIGH_LEVEL);
162     KeLowerIrql(Irql);
163     CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
164 
165     /* now comes the crazy stuff */
166     KeRaiseIrql(HIGH_LEVEL, &Irql);
167       CheckApcs(0, 0, TRUE, HIGH_LEVEL);
168       KeEnterCriticalRegion();
169         CheckApcs(-1, 0, TRUE, HIGH_LEVEL);
170       KeLeaveCriticalRegion();
171       CheckApcs(0, 0, TRUE, HIGH_LEVEL);
172 
173       /* Ke*GuardedRegion assert at > APC_LEVEL */
174       if (!KmtIsCheckedBuild &&
175           !skip(pKeEnterGuardedRegion &&
176                 pKeLeaveGuardedRegion, "Guarded regions not available\n"))
177       {
178           pKeEnterGuardedRegion();
179             CheckApcs(0, -1, TRUE, HIGH_LEVEL);
180           pKeLeaveGuardedRegion();
181       }
182       CheckApcs(0, 0, TRUE, HIGH_LEVEL);
183     KeLowerIrql(Irql);
184     CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
185 
186     if (!KmtIsCheckedBuild &&
187         !skip(pKeEnterGuardedRegion &&
188               pKeLeaveGuardedRegion, "Guarded regions not available\n"))
189     {
190         KeRaiseIrql(HIGH_LEVEL, &Irql);
191         CheckApcs(0, 0, TRUE, HIGH_LEVEL);
192         KeEnterCriticalRegion();
193         CheckApcs(-1, 0, TRUE, HIGH_LEVEL);
194         pKeEnterGuardedRegion();
195         CheckApcs(-1, -1, TRUE, HIGH_LEVEL);
196         KeLowerIrql(Irql);
197         CheckApcs(-1, -1, TRUE, PASSIVE_LEVEL);
198         KeLeaveCriticalRegion();
199         CheckApcs(0, -1, TRUE, PASSIVE_LEVEL);
200         pKeLeaveGuardedRegion();
201         CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
202 
203         pKeEnterGuardedRegion();
204         CheckApcs(0, -1, TRUE, PASSIVE_LEVEL);
205         KeRaiseIrql(HIGH_LEVEL, &Irql);
206         CheckApcs(0, -1, TRUE, HIGH_LEVEL);
207         KeEnterCriticalRegion();
208         CheckApcs(-1, -1, TRUE, HIGH_LEVEL);
209         pKeLeaveGuardedRegion();
210         CheckApcs(-1, 0, TRUE, HIGH_LEVEL);
211         KeLowerIrql(Irql);
212         CheckApcs(-1, 0, FALSE, PASSIVE_LEVEL);
213         KeLeaveCriticalRegion();
214         CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
215 
216         KeEnterCriticalRegion();
217         CheckApcs(-1, 0, FALSE, PASSIVE_LEVEL);
218         KeRaiseIrql(HIGH_LEVEL, &Irql);
219         CheckApcs(-1, 0, TRUE, HIGH_LEVEL);
220         pKeEnterGuardedRegion();
221         CheckApcs(-1, -1, TRUE, HIGH_LEVEL);
222         KeLeaveCriticalRegion();
223         CheckApcs(0, -1, TRUE, HIGH_LEVEL);
224         KeLowerIrql(Irql);
225         CheckApcs(0, -1, TRUE, PASSIVE_LEVEL);
226         pKeLeaveGuardedRegion();
227         CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
228     }
229 
230     KeEnterCriticalRegion();
231     CheckApcs(-1, 0, FALSE, PASSIVE_LEVEL);
232     KeRaiseIrql(HIGH_LEVEL, &Irql);
233     CheckApcs(-1, 0, TRUE, HIGH_LEVEL);
234     KeLeaveCriticalRegion();
235     CheckApcs(0, 0, TRUE, HIGH_LEVEL);
236     KeLowerIrql(Irql);
237     CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
238 }
239