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 VOID 247 NTAPI 248 KiSwapProcess(IN PKPROCESS NewProcess, 249 IN PKPROCESS OldProcess) 250 { 251 PKIPCR Pcr = (PKIPCR)KeGetPcr(); 252 253 #ifdef CONFIG_SMP 254 /* Update active processor mask */ 255 InterlockedXor64((PLONG64)&NewProcess->ActiveProcessors, Pcr->Prcb.SetMember); 256 InterlockedXor64((PLONG64)&OldProcess->ActiveProcessors, Pcr->Prcb.SetMember); 257 #endif 258 259 /* Update CR3 */ 260 __writecr3(NewProcess->DirectoryTableBase[0]); 261 262 /* Update IOPM offset */ 263 Pcr->TssBase->IoMapBase = NewProcess->IopmOffset; 264 } 265 266 #define MAX_SYSCALL_PARAMS 16 267 268 NTSTATUS 269 NtSyscallFailure(void) 270 { 271 /* This is the failure function */ 272 return (NTSTATUS)KeGetCurrentThread()->TrapFrame->Rax; 273 } 274 275 PVOID 276 KiSystemCallHandler( 277 _In_ ULONG64 ReturnAddress, 278 _In_ ULONG64 P2, 279 _In_ ULONG64 P3, 280 _In_ ULONG64 P4) 281 { 282 PKTRAP_FRAME TrapFrame; 283 PKSERVICE_TABLE_DESCRIPTOR DescriptorTable; 284 PKTHREAD Thread; 285 PULONG64 KernelParams, UserParams; 286 ULONG ServiceNumber, Offset, Count; 287 ULONG64 UserRsp; 288 289 /* Get a pointer to the trap frame */ 290 TrapFrame = (PKTRAP_FRAME)((PULONG64)_AddressOfReturnAddress() + 1 + MAX_SYSCALL_PARAMS); 291 292 /* Save some values in the trap frame */ 293 TrapFrame->Rip = ReturnAddress; 294 TrapFrame->Rdx = P2; 295 TrapFrame->R8 = P3; 296 TrapFrame->R9 = P4; 297 298 /* Increase system call count */ 299 __addgsdword(FIELD_OFFSET(KIPCR, Prcb.KeSystemCalls), 1); 300 301 /* Get the current thread */ 302 Thread = KeGetCurrentThread(); 303 304 /* Set previous mode */ 305 Thread->PreviousMode = TrapFrame->PreviousMode = UserMode; 306 307 /* Save the old trap frame and set the new */ 308 TrapFrame->TrapFrame = (ULONG64)Thread->TrapFrame; 309 Thread->TrapFrame = TrapFrame; 310 311 /* We don't have an exception frame yet */ 312 TrapFrame->ExceptionFrame = 0; 313 314 /* Before enabling interrupts get the user rsp from the KPCR */ 315 UserRsp = __readgsqword(FIELD_OFFSET(KIPCR, UserRsp)); 316 TrapFrame->Rsp = UserRsp; 317 318 /* Enable interrupts */ 319 _enable(); 320 321 /* If the usermode rsp was not a usermode address, prepare an exception */ 322 if (UserRsp > MmUserProbeAddress) UserRsp = MmUserProbeAddress; 323 324 /* Get the address of the usermode and kernelmode parameters */ 325 UserParams = (PULONG64)UserRsp + 1; 326 KernelParams = (PULONG64)TrapFrame - MAX_SYSCALL_PARAMS; 327 328 /* Get the system call number from the trap frame and decode it */ 329 ServiceNumber = (ULONG)TrapFrame->Rax; 330 Offset = (ServiceNumber >> SERVICE_TABLE_SHIFT) & SERVICE_TABLE_MASK; 331 ServiceNumber &= SERVICE_NUMBER_MASK; 332 333 /* Check for win32k system calls */ 334 if (Offset & SERVICE_TABLE_TEST) 335 { 336 ULONG GdiBatchCount; 337 338 /* Read the GDI batch count from the TEB */ 339 _SEH2_TRY 340 { 341 GdiBatchCount = NtCurrentTeb()->GdiBatchCount; 342 } 343 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 344 { 345 GdiBatchCount = 0; 346 } 347 348 /* Flush batch, if there are entries */ 349 if (GdiBatchCount != 0) 350 { 351 KeGdiFlushUserBatch(); 352 } 353 } 354 355 /* Get descriptor table */ 356 DescriptorTable = (PVOID)((ULONG_PTR)Thread->ServiceTable + Offset); 357 358 /* Validate the system call number */ 359 if (ServiceNumber >= DescriptorTable->Limit) 360 { 361 /* Check if this is a GUI call */ 362 if (!(Offset & SERVICE_TABLE_TEST)) 363 { 364 /* Fail the call */ 365 TrapFrame->Rax = STATUS_INVALID_SYSTEM_SERVICE; 366 return (PVOID)NtSyscallFailure; 367 } 368 369 /* Convert us to a GUI thread 370 To be entirely correct. we return KiConvertToGuiThread, 371 which allocates a new stack, switches to it, calls 372 PsConvertToGuiThread and resumes in the middle of 373 KiSystemCallEntry64 to restart the system call handling. */ 374 return (PVOID)KiConvertToGuiThread; 375 } 376 377 /* Get stack bytes and calculate argument count */ 378 Count = DescriptorTable->Number[ServiceNumber] / 8; 379 380 __try 381 { 382 switch (Count) 383 { 384 case 16: KernelParams[15] = UserParams[15]; 385 case 15: KernelParams[14] = UserParams[14]; 386 case 14: KernelParams[13] = UserParams[13]; 387 case 13: KernelParams[12] = UserParams[12]; 388 case 12: KernelParams[11] = UserParams[11]; 389 case 11: KernelParams[10] = UserParams[10]; 390 case 10: KernelParams[9] = UserParams[9]; 391 case 9: KernelParams[8] = UserParams[8]; 392 case 8: KernelParams[7] = UserParams[7]; 393 case 7: KernelParams[6] = UserParams[6]; 394 case 6: KernelParams[5] = UserParams[5]; 395 case 5: KernelParams[4] = UserParams[4]; 396 case 4: 397 case 3: 398 case 2: 399 case 1: 400 case 0: 401 break; 402 403 default: 404 __debugbreak(); 405 break; 406 } 407 } 408 __except(1) 409 { 410 TrapFrame->Rax = _SEH2_GetExceptionCode(); 411 return (PVOID)NtSyscallFailure; 412 } 413 414 415 return (PVOID)DescriptorTable->Base[ServiceNumber]; 416 } 417 418 419 // FIXME: we need to 420 VOID 421 KiSystemService(IN PKTHREAD Thread, 422 IN PKTRAP_FRAME TrapFrame, 423 IN ULONG Instruction) 424 { 425 UNIMPLEMENTED; 426 __debugbreak(); 427 } 428 429 NTSYSAPI 430 NTSTATUS 431 NTAPI 432 NtCallbackReturn 433 ( IN PVOID Result OPTIONAL, IN ULONG ResultLength, IN NTSTATUS Status ) 434 { 435 UNIMPLEMENTED; 436 __debugbreak(); 437 return STATUS_UNSUCCESSFUL; 438 } 439 440 NTSTATUS 441 NTAPI 442 NtSetLdtEntries 443 (ULONG Selector1, LDT_ENTRY LdtEntry1, ULONG Selector2, LDT_ENTRY LdtEntry2) 444 { 445 UNIMPLEMENTED; 446 __debugbreak(); 447 return STATUS_UNSUCCESSFUL; 448 } 449 450 NTSTATUS 451 NTAPI 452 NtVdmControl(IN ULONG ControlCode, 453 IN PVOID ControlData) 454 { 455 /* Not supported */ 456 return STATUS_NOT_IMPLEMENTED; 457 } 458 459 NTSTATUS 460 NTAPI 461 KiCallUserMode( 462 IN PVOID *OutputBuffer, 463 IN PULONG OutputLength) 464 { 465 UNIMPLEMENTED; 466 __debugbreak(); 467 return STATUS_UNSUCCESSFUL; 468 } 469 470 ULONG ProcessCount; 471 BOOLEAN CcPfEnablePrefetcher; 472 473 474