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 SIZE_T KeXStateLength = sizeof(XSAVE_FORMAT); 18 19 VOID 20 KiRetireDpcListInDpcStack( 21 PKPRCB Prcb, 22 PVOID DpcStack); 23 24 NTSTATUS 25 KiConvertToGuiThread( 26 VOID); 27 28 _Requires_lock_not_held_(Prcb->PrcbLock) 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 /* Acquire the PRCB lock */ 65 KiAcquirePrcbLock(Prcb); 66 67 /* Capture current thread data */ 68 OldThread = Prcb->CurrentThread; 69 NewThread = Prcb->NextThread; 70 71 /* Set new thread data */ 72 Prcb->NextThread = NULL; 73 Prcb->CurrentThread = NewThread; 74 75 /* The thread is now running */ 76 NewThread->State = Running; 77 OldThread->WaitReason = WrDispatchInt; 78 79 /* Make the old thread ready */ 80 KxQueueReadyThread(OldThread, Prcb); 81 82 /* Swap to the new thread */ 83 KiSwapContext(APC_LEVEL, OldThread); 84 } 85 86 /* Disable interrupts and go back to old irql */ 87 _disable(); 88 KeLowerIrql(OldIrql); 89 } 90 91 PVOID 92 KiSwitchKernelStackHelper( 93 LONG_PTR StackOffset, 94 PVOID OldStackBase); 95 96 /* 97 * Kernel stack layout (example pointers): 98 * 0xFFFFFC0F'2D008000 KTHREAD::StackBase 99 * [XSAVE_AREA size == KeXStateLength = 0x440] 100 * 0xFFFFFC0F'2D007BC0 KTHREAD::StateSaveArea _XSAVE_FORMAT 101 * 0xFFFFFC0F'2D007B90 KTHREAD::InitialStack 102 * [0x190 bytes KTRAP_FRAME] 103 * 0xFFFFFC0F'2D007A00 KTHREAD::TrapFrame 104 * [KSTART_FRAME] or ... 105 * [KSWITCH_FRAME] 106 * 0xFFFFFC0F'2D007230 KTHREAD::KernelStack 107 */ 108 109 PVOID 110 NTAPI 111 KiSwitchKernelStack(PVOID StackBase, PVOID StackLimit) 112 { 113 PKTHREAD CurrentThread; 114 PVOID OldStackBase; 115 LONG_PTR StackOffset; 116 SIZE_T StackSize; 117 PKIPCR Pcr; 118 ULONG Eflags; 119 120 /* Get the current thread */ 121 CurrentThread = KeGetCurrentThread(); 122 123 /* Save the old stack base */ 124 OldStackBase = CurrentThread->StackBase; 125 126 /* Get the size of the current stack */ 127 StackSize = (ULONG_PTR)CurrentThread->StackBase - CurrentThread->StackLimit; 128 ASSERT(StackSize <= (ULONG_PTR)StackBase - (ULONG_PTR)StackLimit); 129 130 /* Copy the current stack contents to the new stack */ 131 RtlCopyMemory((PUCHAR)StackBase - StackSize, 132 (PVOID)CurrentThread->StackLimit, 133 StackSize); 134 135 /* Calculate the offset between the old and the new stack */ 136 StackOffset = (PUCHAR)StackBase - (PUCHAR)CurrentThread->StackBase; 137 138 /* Disable interrupts while messing with the stack */ 139 Eflags = __readeflags(); 140 _disable(); 141 142 /* Set the new trap frame */ 143 CurrentThread->TrapFrame = (PKTRAP_FRAME)Add2Ptr(CurrentThread->TrapFrame, 144 StackOffset); 145 146 /* Set the new initial stack */ 147 CurrentThread->InitialStack = Add2Ptr(CurrentThread->InitialStack, 148 StackOffset); 149 150 /* Set the new stack limits */ 151 CurrentThread->StackBase = StackBase; 152 CurrentThread->StackLimit = (ULONG_PTR)StackLimit; 153 CurrentThread->LargeStack = TRUE; 154 155 /* Adjust RspBase in the PCR */ 156 Pcr = (PKIPCR)KeGetPcr(); 157 Pcr->Prcb.RspBase += StackOffset; 158 159 /* Adjust Rsp0 in the TSS */ 160 Pcr->TssBase->Rsp0 += StackOffset; 161 162 /* Restore interrupts */ 163 __writeeflags(Eflags); 164 165 return OldStackBase; 166 } 167 168 DECLSPEC_NORETURN 169 VOID 170 KiIdleLoop(VOID) 171 { 172 PKPRCB Prcb = KeGetCurrentPrcb(); 173 PKTHREAD OldThread, NewThread; 174 175 /* Now loop forever */ 176 while (TRUE) 177 { 178 /* Start of the idle loop: disable interrupts */ 179 _enable(); 180 YieldProcessor(); 181 YieldProcessor(); 182 _disable(); 183 184 /* Check for pending timers, pending DPCs, or pending ready threads */ 185 if ((Prcb->DpcData[0].DpcQueueDepth) || 186 (Prcb->TimerRequest) || 187 (Prcb->DeferredReadyListHead.Next)) 188 { 189 /* Quiesce the DPC software interrupt */ 190 HalClearSoftwareInterrupt(DISPATCH_LEVEL); 191 192 /* Handle it */ 193 KiRetireDpcList(Prcb); 194 } 195 196 /* Check if a new thread is scheduled for execution */ 197 if (Prcb->NextThread) 198 { 199 /* Enable interrupts */ 200 _enable(); 201 202 /* Capture current thread data */ 203 OldThread = Prcb->CurrentThread; 204 NewThread = Prcb->NextThread; 205 206 /* Set new thread data */ 207 Prcb->NextThread = NULL; 208 Prcb->CurrentThread = NewThread; 209 210 /* The thread is now running */ 211 NewThread->State = Running; 212 213 /* Do the swap at SYNCH_LEVEL */ 214 KfRaiseIrql(SYNCH_LEVEL); 215 216 /* Switch away from the idle thread */ 217 KiSwapContext(APC_LEVEL, OldThread); 218 219 /* Go back to DISPATCH_LEVEL */ 220 KeLowerIrql(DISPATCH_LEVEL); 221 } 222 else 223 { 224 /* Continue staying idle. Note the HAL returns with interrupts on */ 225 Prcb->PowerState.IdleFunction(&Prcb->PowerState); 226 } 227 } 228 } 229 230 VOID 231 NTAPI 232 KiSwapProcess(IN PKPROCESS NewProcess, 233 IN PKPROCESS OldProcess) 234 { 235 PKIPCR Pcr = (PKIPCR)KeGetPcr(); 236 237 #ifdef CONFIG_SMP 238 /* Update active processor mask */ 239 InterlockedXor64((PLONG64)&NewProcess->ActiveProcessors, Pcr->Prcb.SetMember); 240 InterlockedXor64((PLONG64)&OldProcess->ActiveProcessors, Pcr->Prcb.SetMember); 241 #endif 242 243 /* Update CR3 */ 244 __writecr3(NewProcess->DirectoryTableBase[0]); 245 246 /* Update IOPM offset */ 247 Pcr->TssBase->IoMapBase = NewProcess->IopmOffset; 248 } 249 250 #define MAX_SYSCALL_PARAMS 16 251 252 NTSTATUS 253 NtSyscallFailure(void) 254 { 255 /* This is the failure function */ 256 return (NTSTATUS)KeGetCurrentThread()->TrapFrame->Rax; 257 } 258 259 PVOID 260 KiSystemCallHandler( 261 VOID) 262 { 263 PKTRAP_FRAME TrapFrame; 264 PKSERVICE_TABLE_DESCRIPTOR DescriptorTable; 265 PKTHREAD Thread; 266 PULONG64 KernelParams, UserParams; 267 ULONG ServiceNumber, Offset, Count; 268 ULONG64 UserRsp; 269 270 /* Get a pointer to the trap frame */ 271 TrapFrame = (PKTRAP_FRAME)((PULONG64)_AddressOfReturnAddress() + 1 + MAX_SYSCALL_PARAMS); 272 273 /* Increase system call count */ 274 __addgsdword(FIELD_OFFSET(KIPCR, Prcb.KeSystemCalls), 1); 275 276 /* Get the current thread */ 277 Thread = KeGetCurrentThread(); 278 279 /* Set previous mode */ 280 Thread->PreviousMode = TrapFrame->PreviousMode = UserMode; 281 282 /* Save the old trap frame and set the new */ 283 TrapFrame->TrapFrame = (ULONG64)Thread->TrapFrame; 284 Thread->TrapFrame = TrapFrame; 285 286 /* We don't have an exception frame yet */ 287 TrapFrame->ExceptionFrame = 0; 288 289 /* Before enabling interrupts get the user rsp from the KPCR */ 290 UserRsp = __readgsqword(FIELD_OFFSET(KIPCR, UserRsp)); 291 TrapFrame->Rsp = UserRsp; 292 293 /* Enable interrupts */ 294 _enable(); 295 296 /* If the usermode rsp was not a usermode address, prepare an exception */ 297 if (UserRsp > MmUserProbeAddress) UserRsp = MmUserProbeAddress; 298 299 /* Get the address of the usermode and kernelmode parameters */ 300 UserParams = (PULONG64)UserRsp + 1; 301 KernelParams = (PULONG64)TrapFrame - MAX_SYSCALL_PARAMS; 302 303 /* Get the system call number from the trap frame and decode it */ 304 ServiceNumber = (ULONG)TrapFrame->Rax; 305 Offset = (ServiceNumber >> SERVICE_TABLE_SHIFT) & SERVICE_TABLE_MASK; 306 ServiceNumber &= SERVICE_NUMBER_MASK; 307 308 /* Check for win32k system calls */ 309 if (Offset & SERVICE_TABLE_TEST) 310 { 311 ULONG GdiBatchCount; 312 313 /* Read the GDI batch count from the TEB */ 314 _SEH2_TRY 315 { 316 GdiBatchCount = NtCurrentTeb()->GdiBatchCount; 317 } 318 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 319 { 320 GdiBatchCount = 0; 321 } 322 _SEH2_END; 323 324 /* Flush batch, if there are entries */ 325 if (GdiBatchCount != 0) 326 { 327 KeGdiFlushUserBatch(); 328 } 329 } 330 331 /* Get descriptor table */ 332 DescriptorTable = (PVOID)((ULONG_PTR)Thread->ServiceTable + Offset); 333 334 /* Validate the system call number */ 335 if (ServiceNumber >= DescriptorTable->Limit) 336 { 337 /* Check if this is a GUI call */ 338 if (!(Offset & SERVICE_TABLE_TEST)) 339 { 340 /* Fail the call */ 341 TrapFrame->Rax = STATUS_INVALID_SYSTEM_SERVICE; 342 return (PVOID)NtSyscallFailure; 343 } 344 345 /* Convert us to a GUI thread 346 To be entirely correct. we return KiConvertToGuiThread, 347 which allocates a new stack, switches to it, calls 348 PsConvertToGuiThread and resumes in the middle of 349 KiSystemCallEntry64 to restart the system call handling. */ 350 return (PVOID)KiConvertToGuiThread; 351 } 352 353 /* Get stack bytes and calculate argument count */ 354 Count = DescriptorTable->Number[ServiceNumber] / 8; 355 356 _SEH2_TRY 357 { 358 switch (Count) 359 { 360 case 16: KernelParams[15] = UserParams[15]; 361 case 15: KernelParams[14] = UserParams[14]; 362 case 14: KernelParams[13] = UserParams[13]; 363 case 13: KernelParams[12] = UserParams[12]; 364 case 12: KernelParams[11] = UserParams[11]; 365 case 11: KernelParams[10] = UserParams[10]; 366 case 10: KernelParams[9] = UserParams[9]; 367 case 9: KernelParams[8] = UserParams[8]; 368 case 8: KernelParams[7] = UserParams[7]; 369 case 7: KernelParams[6] = UserParams[6]; 370 case 6: KernelParams[5] = UserParams[5]; 371 case 5: KernelParams[4] = UserParams[4]; 372 case 4: 373 case 3: 374 case 2: 375 case 1: 376 case 0: 377 break; 378 379 default: 380 ASSERT(FALSE); 381 break; 382 } 383 } 384 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 385 { 386 TrapFrame->Rax = _SEH2_GetExceptionCode(); 387 return (PVOID)NtSyscallFailure; 388 } 389 _SEH2_END; 390 391 return (PVOID)DescriptorTable->Base[ServiceNumber]; 392 } 393 394 395 // FIXME: we need to 396 VOID 397 KiSystemService(IN PKTHREAD Thread, 398 IN PKTRAP_FRAME TrapFrame, 399 IN ULONG Instruction) 400 { 401 UNIMPLEMENTED; 402 __debugbreak(); 403 } 404 405 NTSTATUS 406 NTAPI 407 NtSetLdtEntries 408 (ULONG Selector1, LDT_ENTRY LdtEntry1, ULONG Selector2, LDT_ENTRY LdtEntry2) 409 { 410 UNIMPLEMENTED; 411 __debugbreak(); 412 return STATUS_UNSUCCESSFUL; 413 } 414 415 NTSTATUS 416 NTAPI 417 NtVdmControl(IN ULONG ControlCode, 418 IN PVOID ControlData) 419 { 420 /* Not supported */ 421 return STATUS_NOT_IMPLEMENTED; 422 } 423 424 425