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