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 DECLSPEC_NORETURN 171 VOID 172 KiIdleLoop(VOID) 173 { 174 PKPRCB Prcb = KeGetCurrentPrcb(); 175 PKTHREAD OldThread, NewThread; 176 177 /* Now loop forever */ 178 while (TRUE) 179 { 180 /* Start of the idle loop: disable interrupts */ 181 _enable(); 182 YieldProcessor(); 183 YieldProcessor(); 184 _disable(); 185 186 /* Check for pending timers, pending DPCs, or pending ready threads */ 187 if ((Prcb->DpcData[0].DpcQueueDepth) || 188 (Prcb->TimerRequest) || 189 (Prcb->DeferredReadyListHead.Next)) 190 { 191 /* Quiesce the DPC software interrupt */ 192 HalClearSoftwareInterrupt(DISPATCH_LEVEL); 193 194 /* Handle it */ 195 KiRetireDpcList(Prcb); 196 } 197 198 /* Check if a new thread is scheduled for execution */ 199 if (Prcb->NextThread) 200 { 201 /* Enable interrupts */ 202 _enable(); 203 204 /* Capture current thread data */ 205 OldThread = Prcb->CurrentThread; 206 NewThread = Prcb->NextThread; 207 208 /* Set new thread data */ 209 Prcb->NextThread = NULL; 210 Prcb->CurrentThread = NewThread; 211 212 /* The thread is now running */ 213 NewThread->State = Running; 214 215 /* Do the swap at SYNCH_LEVEL */ 216 KfRaiseIrql(SYNCH_LEVEL); 217 218 /* Switch away from the idle thread */ 219 KiSwapContext(APC_LEVEL, OldThread); 220 221 /* Go back to DISPATCH_LEVEL */ 222 KeLowerIrql(DISPATCH_LEVEL); 223 } 224 else 225 { 226 /* Continue staying idle. Note the HAL returns with interrupts on */ 227 Prcb->PowerState.IdleFunction(&Prcb->PowerState); 228 } 229 } 230 } 231 232 VOID 233 NTAPI 234 KiSwapProcess(IN PKPROCESS NewProcess, 235 IN PKPROCESS OldProcess) 236 { 237 PKIPCR Pcr = (PKIPCR)KeGetPcr(); 238 239 #ifdef CONFIG_SMP 240 /* Update active processor mask */ 241 InterlockedXor64((PLONG64)&NewProcess->ActiveProcessors, Pcr->Prcb.SetMember); 242 InterlockedXor64((PLONG64)&OldProcess->ActiveProcessors, Pcr->Prcb.SetMember); 243 #endif 244 245 /* Update CR3 */ 246 __writecr3(NewProcess->DirectoryTableBase[0]); 247 248 /* Update IOPM offset */ 249 Pcr->TssBase->IoMapBase = NewProcess->IopmOffset; 250 } 251 252 #define MAX_SYSCALL_PARAMS 16 253 254 NTSTATUS 255 NtSyscallFailure(void) 256 { 257 /* This is the failure function */ 258 return (NTSTATUS)KeGetCurrentThread()->TrapFrame->Rax; 259 } 260 261 PVOID 262 KiSystemCallHandler( 263 _In_ ULONG64 ReturnAddress, 264 _In_ ULONG64 P2, 265 _In_ ULONG64 P3, 266 _In_ ULONG64 P4) 267 { 268 PKTRAP_FRAME TrapFrame; 269 PKSERVICE_TABLE_DESCRIPTOR DescriptorTable; 270 PKTHREAD Thread; 271 PULONG64 KernelParams, UserParams; 272 ULONG ServiceNumber, Offset, Count; 273 ULONG64 UserRsp; 274 275 /* Get a pointer to the trap frame */ 276 TrapFrame = (PKTRAP_FRAME)((PULONG64)_AddressOfReturnAddress() + 1 + MAX_SYSCALL_PARAMS); 277 278 /* Save some values in the trap frame */ 279 TrapFrame->Rip = ReturnAddress; 280 TrapFrame->Rdx = P2; 281 TrapFrame->R8 = P3; 282 TrapFrame->R9 = P4; 283 284 /* Increase system call count */ 285 __addgsdword(FIELD_OFFSET(KIPCR, Prcb.KeSystemCalls), 1); 286 287 /* Get the current thread */ 288 Thread = KeGetCurrentThread(); 289 290 /* Set previous mode */ 291 Thread->PreviousMode = TrapFrame->PreviousMode = UserMode; 292 293 /* Save the old trap frame and set the new */ 294 TrapFrame->TrapFrame = (ULONG64)Thread->TrapFrame; 295 Thread->TrapFrame = TrapFrame; 296 297 /* We don't have an exception frame yet */ 298 TrapFrame->ExceptionFrame = 0; 299 300 /* Before enabling interrupts get the user rsp from the KPCR */ 301 UserRsp = __readgsqword(FIELD_OFFSET(KIPCR, UserRsp)); 302 TrapFrame->Rsp = UserRsp; 303 304 /* Enable interrupts */ 305 _enable(); 306 307 /* If the usermode rsp was not a usermode address, prepare an exception */ 308 if (UserRsp > MmUserProbeAddress) UserRsp = MmUserProbeAddress; 309 310 /* Get the address of the usermode and kernelmode parameters */ 311 UserParams = (PULONG64)UserRsp + 1; 312 KernelParams = (PULONG64)TrapFrame - MAX_SYSCALL_PARAMS; 313 314 /* Get the system call number from the trap frame and decode it */ 315 ServiceNumber = (ULONG)TrapFrame->Rax; 316 Offset = (ServiceNumber >> SERVICE_TABLE_SHIFT) & SERVICE_TABLE_MASK; 317 ServiceNumber &= SERVICE_NUMBER_MASK; 318 319 /* Check for win32k system calls */ 320 if (Offset & SERVICE_TABLE_TEST) 321 { 322 ULONG GdiBatchCount; 323 324 /* Read the GDI batch count from the TEB */ 325 _SEH2_TRY 326 { 327 GdiBatchCount = NtCurrentTeb()->GdiBatchCount; 328 } 329 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 330 { 331 GdiBatchCount = 0; 332 } 333 _SEH2_END; 334 335 /* Flush batch, if there are entries */ 336 if (GdiBatchCount != 0) 337 { 338 KeGdiFlushUserBatch(); 339 } 340 } 341 342 /* Get descriptor table */ 343 DescriptorTable = (PVOID)((ULONG_PTR)Thread->ServiceTable + Offset); 344 345 /* Validate the system call number */ 346 if (ServiceNumber >= DescriptorTable->Limit) 347 { 348 /* Check if this is a GUI call */ 349 if (!(Offset & SERVICE_TABLE_TEST)) 350 { 351 /* Fail the call */ 352 TrapFrame->Rax = STATUS_INVALID_SYSTEM_SERVICE; 353 return (PVOID)NtSyscallFailure; 354 } 355 356 /* Convert us to a GUI thread 357 To be entirely correct. we return KiConvertToGuiThread, 358 which allocates a new stack, switches to it, calls 359 PsConvertToGuiThread and resumes in the middle of 360 KiSystemCallEntry64 to restart the system call handling. */ 361 return (PVOID)KiConvertToGuiThread; 362 } 363 364 /* Get stack bytes and calculate argument count */ 365 Count = DescriptorTable->Number[ServiceNumber] / 8; 366 367 _SEH2_TRY 368 { 369 switch (Count) 370 { 371 case 16: KernelParams[15] = UserParams[15]; 372 case 15: KernelParams[14] = UserParams[14]; 373 case 14: KernelParams[13] = UserParams[13]; 374 case 13: KernelParams[12] = UserParams[12]; 375 case 12: KernelParams[11] = UserParams[11]; 376 case 11: KernelParams[10] = UserParams[10]; 377 case 10: KernelParams[9] = UserParams[9]; 378 case 9: KernelParams[8] = UserParams[8]; 379 case 8: KernelParams[7] = UserParams[7]; 380 case 7: KernelParams[6] = UserParams[6]; 381 case 6: KernelParams[5] = UserParams[5]; 382 case 5: KernelParams[4] = UserParams[4]; 383 case 4: 384 case 3: 385 case 2: 386 case 1: 387 case 0: 388 break; 389 390 default: 391 __debugbreak(); 392 break; 393 } 394 } 395 _SEH2_EXCEPT(1) 396 { 397 TrapFrame->Rax = _SEH2_GetExceptionCode(); 398 return (PVOID)NtSyscallFailure; 399 } 400 _SEH2_END; 401 402 return (PVOID)DescriptorTable->Base[ServiceNumber]; 403 } 404 405 406 // FIXME: we need to 407 VOID 408 KiSystemService(IN PKTHREAD Thread, 409 IN PKTRAP_FRAME TrapFrame, 410 IN ULONG Instruction) 411 { 412 UNIMPLEMENTED; 413 __debugbreak(); 414 } 415 416 NTSTATUS 417 NTAPI 418 NtSetLdtEntries 419 (ULONG Selector1, LDT_ENTRY LdtEntry1, ULONG Selector2, LDT_ENTRY LdtEntry2) 420 { 421 UNIMPLEMENTED; 422 __debugbreak(); 423 return STATUS_UNSUCCESSFUL; 424 } 425 426 NTSTATUS 427 NTAPI 428 NtVdmControl(IN ULONG ControlCode, 429 IN PVOID ControlData) 430 { 431 /* Not supported */ 432 return STATUS_NOT_IMPLEMENTED; 433 } 434 435 436