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