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