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