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