xref: /reactos/ntoskrnl/ke/arm/usercall.c (revision c2c66aff)
1 /*
2  * PROJECT:         ReactOS Kernel
3  * LICENSE:         BSD - See COPYING.ARM in the top level directory
4  * FILE:            ntoskrnl/ke/arm/usercall.c
5  * PURPOSE:         Implements system calls and user-mode callbacks for ARM
6  * PROGRAMMERS:     ReactOS Portable Systems Group
7  */
8 
9 /* INCLUDES *******************************************************************/
10 
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14 
15 /* GLOBALS ********************************************************************/
16 
17 //
18 // System call wrapper generator
19 //
20 #define BUILD_SYSCALLS \
21 SYSCALL(00, ()) \
22 SYSCALL(01, (_1)) \
23 SYSCALL(02, (_1, _2)) \
24 SYSCALL(03, (_1, _2, _3)) \
25 SYSCALL(04, (_1, _2, _3, _4 )) \
26 SYSCALL(05, (_1, _2, _3, _4, _5)) \
27 SYSCALL(06, (_1, _2, _3, _4, _5, _6)) \
28 SYSCALL(07, (_1, _2, _3, _4, _5, _6, _7)) \
29 SYSCALL(08, (_1, _2, _3, _4, _5, _6, _7, _8)) \
30 SYSCALL(09, (_1, _2, _3, _4, _5, _6, _7, _8, _9)) \
31 SYSCALL(0A, (_1, _2, _3, _4, _5, _6, _7, _8, _9, a)) \
32 SYSCALL(0B, (_1, _2, _3, _4, _5, _6, _7, _8, _9, a, b)) \
33 SYSCALL(0C, (_1, _2, _3, _4, _5, _6, _7, _8, _9, a, b, c)) \
34 SYSCALL(0D, (_1, _2, _3, _4, _5, _6, _7, _8, _9, a, b, c, d)) \
35 SYSCALL(0E, (_1, _2, _3, _4, _5, _6, _7, _8, _9, a, b, c, d, e)) \
36 SYSCALL(0F, (_1, _2, _3, _4, _5, _6, _7, _8, _9, a, b, c, d, e, f)) \
37 SYSCALL(10, (_1, _2, _3, _4, _5, _6, _7, _8, _9, a, b, c, d, e, f, _10)) \
38 SYSCALL(11, (_1, _2, _3, _4, _5, _6, _7, _8, _9, a, b, c, d, e, f, _10, _11))
39 
40 //
41 // Generate function pointer definitions
42 //
43 #define PROTO
44 #include "ke_i.h"
45 BUILD_SYSCALLS
46 
47 //
48 // Generate function code
49 //
50 #define FUNC
51 #include "ke_i.h"
52 BUILD_SYSCALLS
53 
54 /* SYSTEM CALL STUBS **********************************************************/
55 
56 typedef NTSTATUS (*PKI_SYSCALL_PARAM_HANDLER)(IN PVOID p, IN PVOID *g);
57 PKI_SYSCALL_PARAM_HANDLER KiSyscallHandlers[0x12] =
58 {
59     KiSyscall00Param,
60     KiSyscall01Param,
61     KiSyscall02Param,
62     KiSyscall03Param,
63     KiSyscall04Param,
64     KiSyscall05Param,
65     KiSyscall06Param,
66     KiSyscall07Param,
67     KiSyscall08Param,
68     KiSyscall09Param,
69     KiSyscall0AParam,
70     KiSyscall0BParam,
71     KiSyscall0CParam,
72     KiSyscall0DParam,
73     KiSyscall0EParam,
74     KiSyscall0FParam,
75     KiSyscall10Param,
76     KiSyscall11Param,
77 };
78 
79 /* FUNCIONS *******************************************************************/
80 
81 VOID
82 KiSystemService(IN PKTHREAD Thread,
83                 IN PKTRAP_FRAME TrapFrame,
84                 IN ULONG Instruction)
85 {
86     ULONG Id, Number, ArgumentCount, i;
87     PKPCR Pcr;
88     ULONG_PTR ServiceTable, Offset;
89     PKSERVICE_TABLE_DESCRIPTOR DescriptorTable;
90     PVOID SystemCall;
91     PVOID* Argument;
92     PVOID Arguments[0x11]; // Maximum 17 arguments
93     KIRQL OldIrql;
94     ASSERT(TrapFrame->Reserved == 0xBADB0D00);
95 
96     //
97     // Increase count of system calls
98     //
99     Pcr = KeGetPcr();
100     Pcr->CurrentPrcb->KeSystemCalls++;
101 
102     //
103     // Get the system call ID
104     //
105     Id = Instruction & 0xFFFFF;
106     //DPRINT1("[SWI] (%x) %p (%d) \n", Id, Thread, Thread->PreviousMode);
107 
108     //
109     // Get the descriptor table
110     //
111     ServiceTable = (ULONG_PTR)Thread->ServiceTable;
112     Offset = ((Id >> SERVICE_TABLE_SHIFT) & SERVICE_TABLE_MASK);
113     ServiceTable += Offset;
114     DescriptorTable = (PVOID)ServiceTable;
115 
116     //
117     // Get the service call number and validate it
118     //
119     Number = Id & SERVICE_NUMBER_MASK;
120     if (Number > DescriptorTable->Limit)
121     {
122         //
123         // Check if this is a GUI call
124         //
125         UNIMPLEMENTED;
126         ASSERT(FALSE);
127     }
128 
129     //
130     // Save the function responsible for handling this system call
131     //
132     SystemCall = (PVOID)DescriptorTable->Base[Number];
133 
134     //
135     // Check if this is a GUI call
136     //
137     if (Offset & SERVICE_TABLE_TEST)
138     {
139         //
140         // TODO
141         //
142         UNIMPLEMENTED;
143         ASSERT(FALSE);
144     }
145 
146     //
147     // Check how many arguments this system call takes
148     //
149     ArgumentCount = DescriptorTable->Number[Number] / 4;
150     ASSERT(ArgumentCount <= 17);
151 
152     //
153     // Copy the register-arguments first
154     // First four arguments are in a1, a2, a3, a4
155     //
156     Argument = (PVOID*)&TrapFrame->R0;
157     for (i = 0; (i < ArgumentCount) && (i < 4); i++)
158     {
159         //
160         // Copy them into the kernel stack
161         //
162         Arguments[i] = *Argument;
163         Argument++;
164     }
165 
166     //
167     // If more than four, we'll have some on the user stack
168     //
169     if (ArgumentCount > 4)
170     {
171         //
172         // Check where the stack is
173         //
174         if (Thread->PreviousMode == UserMode)
175         {
176             //
177             // FIXME-USER: Validate the user stack
178             //
179             ASSERT(FALSE);
180             Argument = (PVOID*)TrapFrame->Sp;
181         }
182         else
183         {
184             //
185             // We were called from the kernel
186             //
187             Argument = (PVOID*)(TrapFrame + 1);
188         }
189 
190         //
191         // Copy the rest
192         //
193         for (i = 4; i < ArgumentCount; i++)
194         {
195             //
196             // Copy into kernel stack
197             //
198             Arguments[i] = *Argument;
199             Argument++;
200         }
201     }
202 
203     //
204     // We can safely enable interrupts here
205     //
206     _enable();
207 
208     //
209     // Do the system call and save result in EAX
210     //
211     TrapFrame->R0 = KiSyscallHandlers[ArgumentCount]((PVOID)SystemCall,
212                                                      (PVOID)Arguments);
213 
214     //
215     // Check if this was a user call
216     //
217     if (KiGetPreviousMode(TrapFrame) == UserMode)
218     {
219         //
220         // Make sure we didn't return at elevated IRQL
221         //
222         OldIrql = KeGetCurrentIrql();
223         if (OldIrql != PASSIVE_LEVEL)
224         {
225             //
226             // Forcibly put us in a sane state
227             //
228             KeGetPcr()->CurrentIrql = 0;
229             _disable();
230 
231             //
232             // Fail
233             //
234             KeBugCheckEx(IRQL_GT_ZERO_AT_SYSTEM_SERVICE,
235                          (ULONG_PTR)SystemCall,
236                          OldIrql,
237                          0,
238                          0);
239         }
240 
241         //
242         // Make sure we're not attached and that APCs are not disabled
243         //
244         if ((KeGetCurrentThread()->ApcStateIndex != CurrentApcEnvironment) ||
245             (KeGetCurrentThread()->CombinedApcDisable != 0))
246         {
247             //
248             // Fail
249             //
250             KeBugCheckEx(APC_INDEX_MISMATCH,
251                          (ULONG_PTR)SystemCall,
252                          KeGetCurrentThread()->ApcStateIndex,
253                          KeGetCurrentThread()->CombinedApcDisable,
254                          0);
255         }
256     }
257 
258     //
259     // Restore the old trap frame
260     //
261     Thread->TrapFrame = KiGetLinkedTrapFrame(TrapFrame);
262 }
263 
264 VOID
265 NTAPI
266 KiInitializeUserApc(IN PKEXCEPTION_FRAME ExceptionFrame,
267                     IN PKTRAP_FRAME TrapFrame,
268                     IN PKNORMAL_ROUTINE NormalRoutine,
269                     IN PVOID NormalContext,
270                     IN PVOID SystemArgument1,
271                     IN PVOID SystemArgument2)
272 {
273     CONTEXT Context;
274     ULONG_PTR Stack;
275     ULONG ContextLength;
276     DPRINT1("User APC: %p %p %p\n", NormalContext, SystemArgument1, SystemArgument2);
277 
278     //
279     // Build the user mode context
280     //
281     Context.ContextFlags = CONTEXT_FULL;
282     KeTrapFrameToContext(TrapFrame, ExceptionFrame, &Context);
283 
284     //
285     // Setup the context on the user stack
286     //
287     ContextLength = sizeof(CONTEXT);
288     Stack = (ULONG_PTR)(Context.Sp & ~7) - ContextLength;
289 
290     //
291     // Make sure the stack is valid, and copy the context
292     //
293     ProbeForWrite((PVOID)Stack, ContextLength, sizeof(QUAD));
294     RtlMoveMemory((PVOID)Stack, &Context, sizeof(CONTEXT));
295 
296     //
297     // Setup the trap frame when we return to user mode
298     //
299     TrapFrame->R0 = (ULONG)NormalContext;
300     TrapFrame->R1 = (ULONG)SystemArgument1;
301     TrapFrame->R2 = (ULONG)SystemArgument2;
302     TrapFrame->R3 = (ULONG)NormalRoutine;
303     TrapFrame->Sp = Stack;
304     TrapFrame->Lr = (ULONG)KeUserApcDispatcher;
305 }
306 
307 NTSTATUS
308 NTAPI
309 KeUserModeCallback(IN ULONG RoutineIndex,
310                    IN PVOID Argument,
311                    IN ULONG ArgumentLength,
312                    OUT PVOID *Result,
313                    OUT PULONG ResultLength)
314 {
315     ASSERT(FALSE);
316     return STATUS_NOT_IMPLEMENTED;
317 }
318 
319 NTSTATUS
320 NTAPI
321 KiCallUserMode(
322     IN PVOID *OutputBuffer,
323     IN PULONG OutputLength)
324 {
325     ASSERT(FALSE);
326     return STATUS_NOT_IMPLEMENTED;
327 }
328 
329 NTSTATUS
330 NTAPI
331 NtCallbackReturn(
332     _In_ PVOID Result,
333     _In_ ULONG ResultLength,
334     _In_ NTSTATUS CallbackStatus)
335 {
336     ASSERT(FALSE);
337     return STATUS_NOT_IMPLEMENTED;
338 }
339 
340