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 VOID) 264 { 265 PKTRAP_FRAME TrapFrame; 266 PKSERVICE_TABLE_DESCRIPTOR DescriptorTable; 267 PKTHREAD Thread; 268 PULONG64 KernelParams, UserParams; 269 ULONG ServiceNumber, Offset, Count; 270 ULONG64 UserRsp; 271 272 /* Get a pointer to the trap frame */ 273 TrapFrame = (PKTRAP_FRAME)((PULONG64)_AddressOfReturnAddress() + 1 + MAX_SYSCALL_PARAMS); 274 275 /* Increase system call count */ 276 __addgsdword(FIELD_OFFSET(KIPCR, Prcb.KeSystemCalls), 1); 277 278 /* Get the current thread */ 279 Thread = KeGetCurrentThread(); 280 281 /* Set previous mode */ 282 Thread->PreviousMode = TrapFrame->PreviousMode = UserMode; 283 284 /* Save the old trap frame and set the new */ 285 TrapFrame->TrapFrame = (ULONG64)Thread->TrapFrame; 286 Thread->TrapFrame = TrapFrame; 287 288 /* We don't have an exception frame yet */ 289 TrapFrame->ExceptionFrame = 0; 290 291 /* Before enabling interrupts get the user rsp from the KPCR */ 292 UserRsp = __readgsqword(FIELD_OFFSET(KIPCR, UserRsp)); 293 TrapFrame->Rsp = UserRsp; 294 295 /* Enable interrupts */ 296 _enable(); 297 298 /* If the usermode rsp was not a usermode address, prepare an exception */ 299 if (UserRsp > MmUserProbeAddress) UserRsp = MmUserProbeAddress; 300 301 /* Get the address of the usermode and kernelmode parameters */ 302 UserParams = (PULONG64)UserRsp + 1; 303 KernelParams = (PULONG64)TrapFrame - MAX_SYSCALL_PARAMS; 304 305 /* Get the system call number from the trap frame and decode it */ 306 ServiceNumber = (ULONG)TrapFrame->Rax; 307 Offset = (ServiceNumber >> SERVICE_TABLE_SHIFT) & SERVICE_TABLE_MASK; 308 ServiceNumber &= SERVICE_NUMBER_MASK; 309 310 /* Check for win32k system calls */ 311 if (Offset & SERVICE_TABLE_TEST) 312 { 313 ULONG GdiBatchCount; 314 315 /* Read the GDI batch count from the TEB */ 316 _SEH2_TRY 317 { 318 GdiBatchCount = NtCurrentTeb()->GdiBatchCount; 319 } 320 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 321 { 322 GdiBatchCount = 0; 323 } 324 _SEH2_END; 325 326 /* Flush batch, if there are entries */ 327 if (GdiBatchCount != 0) 328 { 329 KeGdiFlushUserBatch(); 330 } 331 } 332 333 /* Get descriptor table */ 334 DescriptorTable = (PVOID)((ULONG_PTR)Thread->ServiceTable + Offset); 335 336 /* Validate the system call number */ 337 if (ServiceNumber >= DescriptorTable->Limit) 338 { 339 /* Check if this is a GUI call */ 340 if (!(Offset & SERVICE_TABLE_TEST)) 341 { 342 /* Fail the call */ 343 TrapFrame->Rax = STATUS_INVALID_SYSTEM_SERVICE; 344 return (PVOID)NtSyscallFailure; 345 } 346 347 /* Convert us to a GUI thread 348 To be entirely correct. we return KiConvertToGuiThread, 349 which allocates a new stack, switches to it, calls 350 PsConvertToGuiThread and resumes in the middle of 351 KiSystemCallEntry64 to restart the system call handling. */ 352 return (PVOID)KiConvertToGuiThread; 353 } 354 355 /* Get stack bytes and calculate argument count */ 356 Count = DescriptorTable->Number[ServiceNumber] / 8; 357 358 _SEH2_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: 375 case 3: 376 case 2: 377 case 1: 378 case 0: 379 break; 380 381 default: 382 ASSERT(FALSE); 383 break; 384 } 385 } 386 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 387 { 388 TrapFrame->Rax = _SEH2_GetExceptionCode(); 389 return (PVOID)NtSyscallFailure; 390 } 391 _SEH2_END; 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 NTSTATUS 408 NTAPI 409 NtSetLdtEntries 410 (ULONG Selector1, LDT_ENTRY LdtEntry1, ULONG Selector2, LDT_ENTRY LdtEntry2) 411 { 412 UNIMPLEMENTED; 413 __debugbreak(); 414 return STATUS_UNSUCCESSFUL; 415 } 416 417 NTSTATUS 418 NTAPI 419 NtVdmControl(IN ULONG ControlCode, 420 IN PVOID ControlData) 421 { 422 /* Not supported */ 423 return STATUS_NOT_IMPLEMENTED; 424 } 425 426 427