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
9 /* INCLUDES *******************************************************************/
12 #include <internal/arm/ksarm.h>
16 /* GLOBALS ********************************************************************/
19 // System call wrapper generator
21 #define BUILD_SYSCALLS \
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))
42 // Generate function pointer definitions
49 // Generate function code
55 /* SYSTEM CALL STUBS **********************************************************/
57 typedef NTSTATUS (*PKI_SYSCALL_PARAM_HANDLER
)(IN PVOID p
, IN PVOID
*g
);
58 PKI_SYSCALL_PARAM_HANDLER KiSyscallHandlers
[0x12] =
80 /* FUNCIONS *******************************************************************/
83 KiSystemService(IN PKTHREAD Thread
,
84 IN PKTRAP_FRAME TrapFrame
,
87 ULONG Id
, Number
, ArgumentCount
, i
;
89 ULONG_PTR ServiceTable
, Offset
;
90 PKSERVICE_TABLE_DESCRIPTOR DescriptorTable
;
93 PVOID Arguments
[0x11]; // Maximum 17 arguments
95 ASSERT(TrapFrame
->DbgArgMark
== 0xBADB0D00);
98 // Increase count of system calls
100 Pcr
= (PKPCR
)KeGetPcr();
101 Pcr
->Prcb
->KeSystemCalls
++;
104 // Get the system call ID
106 Id
= Instruction
& 0xFFFFF;
107 //DPRINT1("[SWI] (%x) %p (%d) \n", Id, Thread, Thread->PreviousMode);
110 // Get the descriptor table
112 ServiceTable
= (ULONG_PTR
)Thread
->ServiceTable
;
113 Offset
= ((Id
>> SERVICE_TABLE_SHIFT
) & SERVICE_TABLE_MASK
);
114 ServiceTable
+= Offset
;
115 DescriptorTable
= (PVOID
)ServiceTable
;
118 // Get the service call number and validate it
120 Number
= Id
& SERVICE_NUMBER_MASK
;
121 if (Number
> DescriptorTable
->Limit
)
124 // Check if this is a GUI call
131 // Save the function responsible for handling this system call
133 SystemCall
= (PVOID
)DescriptorTable
->Base
[Number
];
136 // Check if this is a GUI call
138 if (Offset
& SERVICE_TABLE_TEST
)
148 // Check how many arguments this system call takes
150 ArgumentCount
= DescriptorTable
->Number
[Number
] / 4;
151 ASSERT(ArgumentCount
<= 17);
154 // Copy the register-arguments first
155 // First four arguments are in a1, a2, a3, a4
157 Argument
= (PVOID
*)&TrapFrame
->R0
;
158 for (i
= 0; (i
< ArgumentCount
) && (i
< 4); i
++)
161 // Copy them into the kernel stack
163 Arguments
[i
] = *Argument
;
168 // If more than four, we'll have some on the user stack
170 if (ArgumentCount
> 4)
173 // Check where the stack is
175 if (Thread
->PreviousMode
== UserMode
)
178 // FIXME-USER: Validate the user stack
181 Argument
= (PVOID
*)TrapFrame
->UserSp
;
186 // We were called from the kernel
188 Argument
= (PVOID
*)(TrapFrame
+ 1);
194 for (i
= 4; i
< ArgumentCount
; i
++)
197 // Copy into kernel stack
199 Arguments
[i
] = *Argument
;
205 // We can safely enable interrupts here
210 // Do the system call and save result in EAX
212 TrapFrame
->R0
= KiSyscallHandlers
[ArgumentCount
]((PVOID
)SystemCall
,
216 // Check if this was a user call
218 if (KiGetPreviousMode(TrapFrame
) == UserMode
)
221 // Make sure we didn't return at elevated IRQL
223 OldIrql
= KeGetCurrentIrql();
224 if (OldIrql
!= PASSIVE_LEVEL
)
227 // Forcibly put us in a sane state
229 KeGetPcr()->CurrentIrql
= 0;
235 KeBugCheckEx(IRQL_GT_ZERO_AT_SYSTEM_SERVICE
,
236 (ULONG_PTR
)SystemCall
,
243 // Make sure we're not attached and that APCs are not disabled
245 if ((KeGetCurrentThread()->ApcStateIndex
!= CurrentApcEnvironment
) ||
246 (KeGetCurrentThread()->CombinedApcDisable
!= 0))
251 KeBugCheckEx(APC_INDEX_MISMATCH
,
252 (ULONG_PTR
)SystemCall
,
253 KeGetCurrentThread()->ApcStateIndex
,
254 KeGetCurrentThread()->CombinedApcDisable
,
260 // Restore the old trap frame
262 Thread
->TrapFrame
= (PKTRAP_FRAME
)TrapFrame
->PreviousTrapFrame
;
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
)
277 DPRINT1("User APC: %p %p %p\n", NormalContext
, SystemArgument1
, SystemArgument2
);
280 // Build the user mode context
282 Context
.ContextFlags
= CONTEXT_FULL
;
283 KeTrapFrameToContext(TrapFrame
, ExceptionFrame
, &Context
);
286 // Setup the context on the user stack
288 ContextLength
= sizeof(CONTEXT
);
289 Stack
= (ULONG_PTR
)(Context
.Sp
& ~7) - ContextLength
;
292 // Make sure the stack is valid, and copy the context
294 ProbeForWrite((PVOID
)Stack
, ContextLength
, sizeof(QUAD
));
295 RtlMoveMemory((PVOID
)Stack
, &Context
, sizeof(CONTEXT
));
298 // Setup the trap frame when we return to user mode
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
;