1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL - See COPYING in the top level directory 4 * PURPOSE: stubs 5 * PROGRAMMERS: Timo Kreuzer (timo.kreuzer@reactos.org) 6 */ 7 8 /* INCLUDES ******************************************************************/ 9 10 #include <ntoskrnl.h> 11 12 #define NDEBUG 13 #include <debug.h> 14 15 VOID 16 KiRetireDpcListInDpcStack( 17 PKPRCB Prcb, 18 PVOID DpcStack); 19 20 VOID 21 NTAPI 22 KiDpcInterruptHandler(VOID) 23 { 24 PKPRCB Prcb = KeGetCurrentPrcb(); 25 PKTHREAD NewThread, OldThread; 26 KIRQL OldIrql; 27 28 /* Raise to DISPATCH_LEVEL */ 29 OldIrql = KfRaiseIrql(DISPATCH_LEVEL); 30 31 /* Send an EOI */ 32 KiSendEOI(); 33 34 /* Check for pending timers, pending DPCs, or pending ready threads */ 35 if ((Prcb->DpcData[0].DpcQueueDepth) || 36 (Prcb->TimerRequest) || 37 (Prcb->DeferredReadyListHead.Next)) 38 { 39 /* Retire DPCs while under the DPC stack */ 40 KiRetireDpcListInDpcStack(Prcb, Prcb->DpcStack); 41 } 42 43 /* Enable interrupts */ 44 _enable(); 45 46 /* Check for quantum end */ 47 if (Prcb->QuantumEnd) 48 { 49 /* Handle quantum end */ 50 Prcb->QuantumEnd = FALSE; 51 KiQuantumEnd(); 52 } 53 else if (Prcb->NextThread) 54 { 55 /* Capture current thread data */ 56 OldThread = Prcb->CurrentThread; 57 NewThread = Prcb->NextThread; 58 59 /* Set new thread data */ 60 Prcb->NextThread = NULL; 61 Prcb->CurrentThread = NewThread; 62 63 /* The thread is now running */ 64 NewThread->State = Running; 65 OldThread->WaitReason = WrDispatchInt; 66 67 /* Make the old thread ready */ 68 KxQueueReadyThread(OldThread, Prcb); 69 70 /* Swap to the new thread */ 71 KiSwapContext(APC_LEVEL, OldThread); 72 } 73 74 /* Go back to old irql and disable interrupts */ 75 KeLowerIrql(OldIrql); 76 _disable(); 77 } 78 79 80 VOID 81 FASTCALL 82 KeZeroPages(IN PVOID Address, 83 IN ULONG Size) 84 { 85 /* Not using XMMI in this routine */ 86 RtlZeroMemory(Address, Size); 87 } 88 89 PVOID 90 NTAPI 91 KeSwitchKernelStack(PVOID StackBase, PVOID StackLimit) 92 { 93 UNIMPLEMENTED; 94 __debugbreak(); 95 return NULL; 96 } 97 98 NTSTATUS 99 NTAPI 100 KeUserModeCallback(IN ULONG RoutineIndex, 101 IN PVOID Argument, 102 IN ULONG ArgumentLength, 103 OUT PVOID *Result, 104 OUT PULONG ResultLength) 105 { 106 UNIMPLEMENTED; 107 __debugbreak(); 108 return STATUS_UNSUCCESSFUL; 109 } 110 111 VOID 112 FASTCALL 113 KiIdleLoop(VOID) 114 { 115 PKPRCB Prcb = KeGetCurrentPrcb(); 116 PKTHREAD OldThread, NewThread; 117 118 /* Now loop forever */ 119 while (TRUE) 120 { 121 /* Start of the idle loop: disable interrupts */ 122 _enable(); 123 YieldProcessor(); 124 YieldProcessor(); 125 _disable(); 126 127 /* Check for pending timers, pending DPCs, or pending ready threads */ 128 if ((Prcb->DpcData[0].DpcQueueDepth) || 129 (Prcb->TimerRequest) || 130 (Prcb->DeferredReadyListHead.Next)) 131 { 132 /* Quiesce the DPC software interrupt */ 133 HalClearSoftwareInterrupt(DISPATCH_LEVEL); 134 135 /* Handle it */ 136 KiRetireDpcList(Prcb); 137 } 138 139 /* Check if a new thread is scheduled for execution */ 140 if (Prcb->NextThread) 141 { 142 /* Enable interrupts */ 143 _enable(); 144 145 /* Capture current thread data */ 146 OldThread = Prcb->CurrentThread; 147 NewThread = Prcb->NextThread; 148 149 /* Set new thread data */ 150 Prcb->NextThread = NULL; 151 Prcb->CurrentThread = NewThread; 152 153 /* The thread is now running */ 154 NewThread->State = Running; 155 156 /* Do the swap at SYNCH_LEVEL */ 157 KfRaiseIrql(SYNCH_LEVEL); 158 159 /* Switch away from the idle thread */ 160 KiSwapContext(APC_LEVEL, OldThread); 161 162 /* Go back to DISPATCH_LEVEL */ 163 KeLowerIrql(DISPATCH_LEVEL); 164 } 165 else 166 { 167 /* Continue staying idle. Note the HAL returns with interrupts on */ 168 Prcb->PowerState.IdleFunction(&Prcb->PowerState); 169 } 170 } 171 } 172 173 174 /*! \name KiInitializeUserApc 175 * 176 * \brief 177 * Prepares the current trap frame (which must have come from user mode) 178 * with the ntdll.KiUserApcDispatcher entrypoint, copying a CONTEXT 179 * record with the context from the old trap frame to the threads user 180 * mode stack. 181 * 182 * \param ExceptionFrame 183 * \param TrapFrame 184 * \param NormalRoutine 185 * \param NormalContext 186 * \param SystemArgument1 187 * \param SystemArgument2 188 * 189 * \remarks 190 * This function is called from KiDeliverApc, when the trap frame came 191 * from user mode. This happens before a systemcall or interrupt exits back 192 * to usermode or when a thread is started from PspUserThreadstartup. 193 * The trap exit code will then leave to KiUserApcDispatcher which in turn 194 * calls the NormalRoutine, passing NormalContext, SystemArgument1 and 195 * SystemArgument2 as parameters. When that function returns, it calls 196 * NtContinue to return back to the kernel, where the old context that was 197 * saved on the usermode stack is restored and execution is transferred 198 * back to usermode, where the original trap originated from. 199 * 200 *--*/ 201 VOID 202 NTAPI 203 KiInitializeUserApc(IN PKEXCEPTION_FRAME ExceptionFrame, 204 IN PKTRAP_FRAME TrapFrame, 205 IN PKNORMAL_ROUTINE NormalRoutine, 206 IN PVOID NormalContext, 207 IN PVOID SystemArgument1, 208 IN PVOID SystemArgument2) 209 { 210 CONTEXT Context = { 0 }; 211 ULONG64 AlignedRsp, Stack; 212 EXCEPTION_RECORD SehExceptRecord; 213 214 /* Sanity check, that the trap frame is from user mode */ 215 ASSERT((TrapFrame->SegCs & MODE_MASK) != KernelMode); 216 217 /* Convert the current trap frame to a context */ 218 Context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS; 219 KeTrapFrameToContext(TrapFrame, ExceptionFrame, &Context); 220 221 /* We jump to KiUserApcDispatcher in ntdll */ 222 TrapFrame->Rip = (ULONG64)KeUserApcDispatcher; 223 224 /* Setup Ring 3 segments */ 225 TrapFrame->SegCs = KGDT64_R3_CODE | RPL_MASK; 226 TrapFrame->SegDs = KGDT64_R3_DATA | RPL_MASK; 227 TrapFrame->SegEs = KGDT64_R3_DATA | RPL_MASK; 228 TrapFrame->SegFs = KGDT64_R3_CMTEB | RPL_MASK; 229 TrapFrame->SegGs = KGDT64_R3_DATA | RPL_MASK; 230 TrapFrame->SegSs = KGDT64_R3_DATA | RPL_MASK; 231 232 /* Sanitize EFLAGS, enable interrupts */ 233 TrapFrame->EFlags = (Context.EFlags & EFLAGS_USER_SANITIZE); 234 TrapFrame->EFlags |= EFLAGS_INTERRUPT_MASK; 235 236 /* Set parameters for KiUserApcDispatcher */ 237 Context.P1Home = (ULONG64)NormalContext; 238 Context.P2Home = (ULONG64)SystemArgument1; 239 Context.P3Home = (ULONG64)SystemArgument2; 240 Context.P4Home = (ULONG64)NormalRoutine; 241 242 /* Check if thread has IOPL and force it enabled if so */ 243 //if (KeGetCurrentThread()->Iopl) TrapFrame->EFlags |= EFLAGS_IOPL; 244 245 /* Align Stack to 16 bytes and allocate space */ 246 AlignedRsp = Context.Rsp & ~15; 247 Stack = AlignedRsp - sizeof(CONTEXT); 248 TrapFrame->Rsp = Stack; 249 250 /* The stack must be 16 byte aligned for KiUserApcDispatcher */ 251 ASSERT((Stack & 15) == 0); 252 253 /* Protect with SEH */ 254 _SEH2_TRY 255 { 256 /* Probe the stack */ 257 ProbeForWrite((PCONTEXT)Stack, sizeof(CONTEXT), 8); 258 259 /* Copy the context */ 260 RtlCopyMemory((PCONTEXT)Stack, &Context, sizeof(CONTEXT)); 261 } 262 _SEH2_EXCEPT((RtlCopyMemory(&SehExceptRecord, _SEH2_GetExceptionInformation()->ExceptionRecord, sizeof(EXCEPTION_RECORD)), EXCEPTION_EXECUTE_HANDLER)) 263 { 264 /* Dispatch the exception */ 265 SehExceptRecord.ExceptionAddress = (PVOID)TrapFrame->Rip; 266 KiDispatchException(&SehExceptRecord, 267 ExceptionFrame, 268 TrapFrame, 269 UserMode, 270 TRUE); 271 } 272 _SEH2_END; 273 } 274 275 VOID 276 NTAPI 277 KiSwapProcess(IN PKPROCESS NewProcess, 278 IN PKPROCESS OldProcess) 279 { 280 PKIPCR Pcr = (PKIPCR)KeGetPcr(); 281 282 #ifdef CONFIG_SMP 283 /* Update active processor mask */ 284 InterlockedXor64((PLONG64)&NewProcess->ActiveProcessors, Pcr->Prcb.SetMember); 285 InterlockedXor64((PLONG64)&OldProcess->ActiveProcessors, Pcr->Prcb.SetMember); 286 #endif 287 288 /* Update CR3 */ 289 __writecr3(NewProcess->DirectoryTableBase[0]); 290 291 /* Update IOPM offset */ 292 Pcr->TssBase->IoMapBase = NewProcess->IopmOffset; 293 } 294 295 #define MAX_SYSCALL_PARAMS 16 296 297 NTSTATUS 298 NtSyscallFailure(void) 299 { 300 /* This is the failure function */ 301 return STATUS_ACCESS_VIOLATION; 302 } 303 304 PVOID 305 KiSystemCallHandler( 306 IN PKTRAP_FRAME TrapFrame, 307 IN ULONG64 P2, 308 IN ULONG64 P3, 309 IN ULONG64 P4) 310 { 311 PKSERVICE_TABLE_DESCRIPTOR DescriptorTable; 312 PKTHREAD Thread; 313 PULONG64 KernelParams, UserParams; 314 ULONG ServiceNumber, Offset, Count; 315 ULONG64 UserRsp; 316 317 DPRINT("Syscall #%ld\n", TrapFrame->Rax); 318 //__debugbreak(); 319 320 /* Increase system call count */ 321 __addgsdword(FIELD_OFFSET(KIPCR, Prcb.KeSystemCalls), 1); 322 323 /* Get the current thread */ 324 Thread = KeGetCurrentThread(); 325 326 /* Set previous mode */ 327 Thread->PreviousMode = TrapFrame->PreviousMode = UserMode; 328 329 /* Save the old trap frame and set the new */ 330 TrapFrame->TrapFrame = (ULONG64)Thread->TrapFrame; 331 Thread->TrapFrame = TrapFrame; 332 333 /* Before enabling interrupts get the user rsp from the KPCR */ 334 UserRsp = __readgsqword(FIELD_OFFSET(KIPCR, UserRsp)); 335 TrapFrame->Rsp = UserRsp; 336 337 /* Enable interrupts */ 338 _enable(); 339 340 /* If the usermode rsp was not a usermode address, prepare an exception */ 341 if (UserRsp > MmUserProbeAddress) UserRsp = MmUserProbeAddress; 342 343 /* Get the address of the usermode and kernelmode parameters */ 344 UserParams = (PULONG64)UserRsp + 1; 345 KernelParams = (PULONG64)TrapFrame - MAX_SYSCALL_PARAMS; 346 347 /* Get the system call number from the trap frame and decode it */ 348 ServiceNumber = (ULONG)TrapFrame->Rax; 349 Offset = (ServiceNumber >> SERVICE_TABLE_SHIFT) & SERVICE_TABLE_MASK; 350 ServiceNumber &= SERVICE_NUMBER_MASK; 351 352 /* Get descriptor table */ 353 DescriptorTable = (PVOID)((ULONG_PTR)Thread->ServiceTable + Offset); 354 355 /* Get stack bytes and calculate argument count */ 356 Count = DescriptorTable->Number[ServiceNumber] / 8; 357 358 __try 359 { 360 switch (Count) 361 { 362 case 16: KernelParams[15] = UserParams[15]; 363 case 15: KernelParams[14] = UserParams[14]; 364 case 14: KernelParams[13] = UserParams[13]; 365 case 13: KernelParams[12] = UserParams[12]; 366 case 12: KernelParams[11] = UserParams[11]; 367 case 11: KernelParams[10] = UserParams[10]; 368 case 10: KernelParams[9] = UserParams[9]; 369 case 9: KernelParams[8] = UserParams[8]; 370 case 8: KernelParams[7] = UserParams[7]; 371 case 7: KernelParams[6] = UserParams[6]; 372 case 6: KernelParams[5] = UserParams[5]; 373 case 5: KernelParams[4] = UserParams[4]; 374 case 4: KernelParams[3] = P4; 375 case 3: KernelParams[2] = P3; 376 case 2: KernelParams[1] = P2; 377 case 1: KernelParams[0] = TrapFrame->R10; 378 case 0: 379 break; 380 381 default: 382 __debugbreak(); 383 break; 384 } 385 } 386 __except(1) 387 { 388 TrapFrame->Rax = _SEH2_GetExceptionCode(); 389 return (PVOID)NtSyscallFailure; 390 } 391 392 393 return (PVOID)DescriptorTable->Base[ServiceNumber]; 394 } 395 396 397 // FIXME: we need to 398 VOID 399 KiSystemService(IN PKTHREAD Thread, 400 IN PKTRAP_FRAME TrapFrame, 401 IN ULONG Instruction) 402 { 403 UNIMPLEMENTED; 404 __debugbreak(); 405 } 406 407 NTSYSAPI 408 NTSTATUS 409 NTAPI 410 NtCallbackReturn 411 ( IN PVOID Result OPTIONAL, IN ULONG ResultLength, IN NTSTATUS Status ) 412 { 413 UNIMPLEMENTED; 414 __debugbreak(); 415 return STATUS_UNSUCCESSFUL; 416 } 417 418 NTSTATUS 419 NTAPI 420 NtSetLdtEntries 421 (ULONG Selector1, LDT_ENTRY LdtEntry1, ULONG Selector2, LDT_ENTRY LdtEntry2) 422 { 423 UNIMPLEMENTED; 424 __debugbreak(); 425 return STATUS_UNSUCCESSFUL; 426 } 427 428 NTSTATUS 429 NTAPI 430 NtVdmControl(IN ULONG ControlCode, 431 IN PVOID ControlData) 432 { 433 /* Not supported */ 434 return STATUS_NOT_IMPLEMENTED; 435 } 436 437 NTSTATUS 438 NTAPI 439 KiCallUserMode( 440 IN PVOID *OutputBuffer, 441 IN PULONG OutputLength) 442 { 443 UNIMPLEMENTED; 444 __debugbreak(); 445 return STATUS_UNSUCCESSFUL; 446 } 447 448 ULONG ProcessCount; 449 BOOLEAN CcPfEnablePrefetcher; 450 451 452