2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ke/process.c
5 * PURPOSE: Kernel Process Management and System Call Tables
6 * PROGRAMMERS: Alex Ionescu
10 /* INCLUDES ******************************************************************/
14 #include <internal/debug.h>
16 /* GLOBALS *******************************************************************/
18 LIST_ENTRY KiProcessListHead
;
19 LIST_ENTRY KiProcessInSwapListHead
, KiProcessOutSwapListHead
;
20 LIST_ENTRY KiStackInSwapListHead
;
23 KSERVICE_TABLE_DESCRIPTOR KeServiceDescriptorTable
[SSDT_MAX_ENTRIES
];
24 KSERVICE_TABLE_DESCRIPTOR KeServiceDescriptorTableShadow
[SSDT_MAX_ENTRIES
];
26 PVOID KeUserApcDispatcher
;
27 PVOID KeUserCallbackDispatcher
;
28 PVOID KeUserExceptionDispatcher
;
29 PVOID KeRaiseUserExceptionDispatcher
;
31 /* PRIVATE FUNCTIONS *********************************************************/
36 UpdatePageDirs(IN PKTHREAD Thread
,
40 * The stack and the thread structure of the current process may be
41 * located in a page which is not present in the page directory of
42 * the process we're attaching to. That would lead to a page fault
43 * when this function returns. However, since the processor can't
44 * call the page fault handler 'cause it can't push EIP on the stack,
45 * this will show up as a stack fault which will crash the entire system.
46 * To prevent this, make sure the page directory of the process we're
47 * attaching to is up-to-date.
49 MmUpdatePageDir((PEPROCESS
)Process
,
50 (PVOID
)Thread
->StackLimit
,
56 KiAttachProcess(IN PKTHREAD Thread
,
58 IN PKLOCK_QUEUE_HANDLE ApcLock
,
59 IN PRKAPC_STATE SavedApcState
)
62 PLIST_ENTRY ListHead
, NextEntry
;
63 PKTHREAD CurrentThread
;
65 ASSERT(Process
!= Thread
->ApcState
.Process
);
67 /* Increase Stack Count */
68 ASSERT(Process
->StackCount
!= MAXULONG_PTR
);
69 Process
->StackCount
++;
71 /* Swap the APC Environment */
72 KiMoveApcState(&Thread
->ApcState
, SavedApcState
);
74 /* Reinitialize Apc State */
75 InitializeListHead(&Thread
->ApcState
.ApcListHead
[KernelMode
]);
76 InitializeListHead(&Thread
->ApcState
.ApcListHead
[UserMode
]);
77 Thread
->ApcState
.Process
= Process
;
78 Thread
->ApcState
.KernelApcInProgress
= FALSE
;
79 Thread
->ApcState
.KernelApcPending
= FALSE
;
80 Thread
->ApcState
.UserApcPending
= FALSE
;
82 /* Update Environment Pointers if needed*/
83 if (SavedApcState
== &Thread
->SavedApcState
)
85 Thread
->ApcStatePointer
[OriginalApcEnvironment
] = &Thread
->
87 Thread
->ApcStatePointer
[AttachedApcEnvironment
] = &Thread
->ApcState
;
88 Thread
->ApcStateIndex
= AttachedApcEnvironment
;
91 /* Check if the process is paged in */
92 if (Process
->State
== ProcessInMemory
)
94 /* Scan the ready list */
96 ListHead
= &Process
->ReadyListHead
;
97 NextEntry
= ListHead
->Flink
;
98 while (NextEntry
!= ListHead
)
101 CurrentThread
= CONTAINING_RECORD(NextEntry
, KTHREAD
, WaitListEntry
);
104 RemoveEntryList(NextEntry
);
105 CurrentThread
->ProcessReadyQueue
= FALSE
;
108 KiReadyThread(CurrentThread
);
110 /* Go to the next one */
111 NextEntry
= ListHead
->Flink
;
115 /* Release dispatcher lock */
116 KiReleaseDispatcherLockFromDpcLevel();
119 KiReleaseApcLockFromDpcLevel(ApcLock
);
122 KiSwapProcess(Process
, SavedApcState
->Process
);
124 /* Exit the dispatcher */
125 KiExitDispatcher(ApcLock
->OldIrql
);
129 DPRINT1("Errr. ReactOS doesn't support paging out processes yet...\n");
136 KeInitializeProcess(IN OUT PKPROCESS Process
,
137 IN KPRIORITY Priority
,
138 IN KAFFINITY Affinity
,
139 IN PLARGE_INTEGER DirectoryTableBase
,
148 /* Initialize the Dispatcher Header */
149 KeInitializeDispatcherHeader(&Process
->Header
,
154 /* Initialize Scheduler Data, Alignment Faults and Set the PDE */
155 Process
->Affinity
= Affinity
;
156 Process
->BasePriority
= (CHAR
)Priority
;
157 Process
->QuantumReset
= 6;
158 Process
->DirectoryTableBase
= *DirectoryTableBase
;
159 Process
->AutoAlignment
= Enable
;
160 Process
->IopmOffset
= KiComputeIopmOffset(IO_ACCESS_MAP_NONE
);
162 /* Initialize the lists */
163 InitializeListHead(&Process
->ThreadListHead
);
164 InitializeListHead(&Process
->ProfileListHead
);
165 InitializeListHead(&Process
->ReadyListHead
);
167 /* Initialize the current State */
168 Process
->State
= ProcessInMemory
;
170 /* Check how many Nodes there are on the system */
172 if (KeNumberNodes
> 1)
174 /* Set the new seed */
175 KeProcessNodeSeed
= (KeProcessNodeSeed
+ 1) / KeNumberNodes
;
176 IdealNode
= KeProcessNodeSeed
;
178 /* Loop every node */
181 /* Check if the affinity matches */
182 if (KeNodeBlock
[IdealNode
]->ProcessorMask
!= Affinity
) break;
184 /* No match, try next Ideal Node and increase node loop index */
188 /* Check if the Ideal Node is beyond the total number of nodes */
189 if (IdealNode
>= KeNumberNodes
)
191 /* Normalize the Ideal Node */
192 IdealNode
-= KeNumberNodes
;
194 } while (i
< KeNumberNodes
);
197 /* Set the ideal node and get the ideal node block */
198 Process
->IdealNode
= IdealNode
;
199 Node
= KeNodeBlock
[IdealNode
];
200 ASSERT(Node
->ProcessorMask
& Affinity
);
202 /* Find the matching affinity set to calculate the thread seed */
203 Affinity
&= Node
->ProcessorMask
;
204 Process
->ThreadSeed
= KeFindNextRightSetAffinity(Node
->Seed
,
206 Node
->Seed
= Process
->ThreadSeed
;
212 KeSetProcess(IN PKPROCESS Process
,
213 IN KPRIORITY Increment
,
218 ASSERT_PROCESS(Process
);
219 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
221 /* Lock Dispatcher */
222 OldIrql
= KiAcquireDispatcherLock();
225 OldState
= Process
->Header
.SignalState
;
227 /* Signal the Process */
228 Process
->Header
.SignalState
= TRUE
;
230 /* Check if was unsignaled and has waiters */
232 !(IsListEmpty(&Process
->Header
.WaitListHead
)))
234 /* Unwait the threads */
235 KxUnwaitThread(&Process
->Header
, Increment
);
238 /* Release Dispatcher Database */
239 KiReleaseDispatcherLock(OldIrql
);
241 /* Return the previous State */
247 KeSetQuantumProcess(IN PKPROCESS Process
,
250 KLOCK_QUEUE_HANDLE ProcessLock
;
251 PLIST_ENTRY NextEntry
, ListHead
;
253 ASSERT_PROCESS(Process
);
254 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
256 /* Lock the process */
257 KiAcquireProcessLock(Process
, &ProcessLock
);
259 /* Set new quantum */
260 Process
->QuantumReset
= Quantum
;
262 /* Loop all child threads */
263 ListHead
= &Process
->ThreadListHead
;
264 NextEntry
= ListHead
->Flink
;
265 while (ListHead
!= NextEntry
)
268 Thread
= CONTAINING_RECORD(NextEntry
, KTHREAD
, ThreadListEntry
);
271 Thread
->QuantumReset
= Quantum
;
273 /* Go to the next one */
274 NextEntry
= NextEntry
->Flink
;
278 KiReleaseProcessLock(&ProcessLock
);
283 KeSetPriorityAndQuantumProcess(IN PKPROCESS Process
,
284 IN KPRIORITY Priority
,
285 IN UCHAR Quantum OPTIONAL
)
287 KLOCK_QUEUE_HANDLE ProcessLock
;
289 PLIST_ENTRY NextEntry
, ListHead
;
290 KPRIORITY NewPriority
, OldPriority
;
292 ASSERT_PROCESS(Process
);
293 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
295 /* Check if the process already has this priority */
296 if (Process
->BasePriority
== Priority
) return Process
->BasePriority
;
298 /* If the caller gave priority 0, normalize to 1 */
299 if (!LOW_PRIORITY
) Priority
= LOW_PRIORITY
+ 1;
301 /* Lock the process */
302 KiAcquireProcessLock(Process
, &ProcessLock
);
304 /* Check if we are modifying the quantum too */
305 if (Quantum
) Process
->QuantumReset
= Quantum
;
307 /* Save the current base priority and update it */
308 OldPriority
= Process
->BasePriority
;
309 Process
->BasePriority
= Priority
;
311 /* Calculate the priority delta */
312 Delta
= Priority
- OldPriority
;
314 /* Set the list head and list entry */
315 ListHead
= &Process
->ThreadListHead
;
316 NextEntry
= ListHead
->Flink
;
318 /* Check if this is a real-time priority */
319 if (Priority
>= LOW_REALTIME_PRIORITY
)
321 /* Loop the thread list */
322 while (NextEntry
!= ListHead
)
325 Thread
= CONTAINING_RECORD(NextEntry
, KTHREAD
, ThreadListEntry
);
327 /* Update the quantum if we had one */
328 if (Quantum
) Thread
->QuantumReset
= Quantum
;
330 /* Acquire the thread lock */
331 KiAcquireThreadLock(Thread
);
333 /* Calculate the new priority */
334 NewPriority
= Thread
->BasePriority
+ Delta
;
335 if (NewPriority
< LOW_REALTIME_PRIORITY
)
337 /* We're in real-time range, don't let it go below */
338 NewPriority
= LOW_REALTIME_PRIORITY
;
340 else if (NewPriority
> HIGH_PRIORITY
)
342 /* We're going beyond the maximum priority, normalize */
343 NewPriority
= HIGH_PRIORITY
;
347 * If priority saturation occured or the old priority was still in
348 * the real-time range, don't do anything.
350 if (!(Thread
->Saturation
) || (OldPriority
< LOW_REALTIME_PRIORITY
))
352 /* Check if we had priority saturation */
353 if (Thread
->Saturation
> 0)
355 /* Boost priority to maximum */
356 NewPriority
= HIGH_PRIORITY
;
358 else if (Thread
->Saturation
< 0)
360 /* If we had negative saturation, set minimum priority */
361 NewPriority
= LOW_REALTIME_PRIORITY
;
364 /* Update priority and quantum */
365 Thread
->BasePriority
= NewPriority
;
366 Thread
->Quantum
= Thread
->QuantumReset
;
368 /* Disable decrements and update priority */
369 Thread
->PriorityDecrement
= 0;
370 KiSetPriorityThread(Thread
, NewPriority
);
373 /* Release the thread lock */
374 KiReleaseThreadLock(Thread
);
376 /* Go to the next thread */
377 NextEntry
= NextEntry
->Flink
;
382 /* Loop the thread list */
383 while (NextEntry
!= ListHead
)
386 Thread
= CONTAINING_RECORD(NextEntry
, KTHREAD
, ThreadListEntry
);
388 /* Update the quantum if we had one */
389 if (Quantum
) Thread
->QuantumReset
= Quantum
;
391 /* Lock the thread */
392 KiAcquireThreadLock(Thread
);
394 /* Calculate the new priority */
395 NewPriority
= Thread
->BasePriority
+ Delta
;
396 if (NewPriority
>= LOW_REALTIME_PRIORITY
)
398 /* We're not real-time range, don't let it enter RT range */
399 NewPriority
= LOW_REALTIME_PRIORITY
- 1;
401 else if (NewPriority
<= LOW_PRIORITY
)
403 /* We're going below the minimum priority, normalize */
408 * If priority saturation occured or the old priority was still in
409 * the real-time range, don't do anything.
411 if (!(Thread
->Saturation
) ||
412 (OldPriority
>= LOW_REALTIME_PRIORITY
))
414 /* Check if we had priority saturation */
415 if (Thread
->Saturation
> 0)
417 /* Boost priority to maximum */
418 NewPriority
= LOW_REALTIME_PRIORITY
- 1;
420 else if (Thread
->Saturation
< 0)
422 /* If we had negative saturation, set minimum priority */
426 /* Update priority and quantum */
427 Thread
->BasePriority
= NewPriority
;
428 Thread
->Quantum
= Thread
->QuantumReset
;
430 /* Disable decrements and update priority */
431 Thread
->PriorityDecrement
= 0;
432 KiSetPriorityThread(Thread
, NewPriority
);
435 /* Release the thread lock */
436 KiReleaseThreadLock(Thread
);
438 /* Go to the next thread */
439 NextEntry
= NextEntry
->Flink
;
443 /* Release Dispatcher Database */
444 KiReleaseDispatcherLockFromDpcLevel();
446 /* Release the process lock */
447 KiReleaseProcessLockFromDpcLevel(&ProcessLock
);
448 KiExitDispatcher(ProcessLock
.OldIrql
);
450 /* Return previous priority */
454 /* PUBLIC FUNCTIONS **********************************************************/
461 KeAttachProcess(IN PKPROCESS Process
)
463 KLOCK_QUEUE_HANDLE ApcLock
;
465 ASSERT_PROCESS(Process
);
466 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
468 /* Make sure that we are in the right page directory */
469 Thread
= KeGetCurrentThread();
470 UpdatePageDirs(Thread
, Process
);
472 /* Check if we're already in that process */
473 if (Thread
->ApcState
.Process
== Process
) return;
475 /* Check if a DPC is executing or if we're already attached */
476 if ((Thread
->ApcStateIndex
!= OriginalApcEnvironment
) ||
477 (KeIsExecutingDpc()))
479 /* Invalid attempt */
480 KEBUGCHECKEX(INVALID_PROCESS_ATTACH_ATTEMPT
,
482 (ULONG_PTR
)Thread
->ApcState
.Process
,
483 Thread
->ApcStateIndex
,
488 /* Acquire APC Lock */
489 KiAcquireApcLock(Thread
, &ApcLock
);
491 /* Acquire the dispatcher lock */
492 KiAcquireDispatcherLockAtDpcLevel();
494 /* Legit attach attempt: do it! */
495 KiAttachProcess(Thread
, Process
, &ApcLock
, &Thread
->SavedApcState
);
504 KeDetachProcess(VOID
)
506 PKTHREAD Thread
= KeGetCurrentThread();
507 KLOCK_QUEUE_HANDLE ApcLock
;
509 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
511 /* Check if it's attached */
512 if (Thread
->ApcStateIndex
== OriginalApcEnvironment
) return;
514 /* Acquire APC Lock */
515 KiAcquireApcLock(Thread
, &ApcLock
);
517 /* Check for invalid attach attempts */
518 if ((Thread
->ApcState
.KernelApcInProgress
) ||
519 !(IsListEmpty(&Thread
->ApcState
.ApcListHead
[KernelMode
])) ||
520 !(IsListEmpty(&Thread
->ApcState
.ApcListHead
[UserMode
])))
522 /* Crash the system */
523 KeBugCheck(INVALID_PROCESS_DETACH_ATTEMPT
);
526 /* Get the process */
527 Process
= Thread
->ApcState
.Process
;
529 /* Acquire dispatcher lock */
530 KiAcquireDispatcherLockAtDpcLevel();
532 /* Decrease the stack count */
533 ASSERT(Process
->StackCount
!= 0);
534 ASSERT(Process
->State
== ProcessInMemory
);
535 Process
->StackCount
--;
537 /* Check if we can swap the process out */
538 if (!Process
->StackCount
)
540 /* FIXME: Swap the process out */
543 /* Release dispatcher lock */
544 KiReleaseDispatcherLockFromDpcLevel();
546 /* Restore the APC State */
547 KiMoveApcState(&Thread
->SavedApcState
, &Thread
->ApcState
);
548 Thread
->SavedApcState
.Process
= NULL
;
549 Thread
->ApcStatePointer
[OriginalApcEnvironment
] = &Thread
->ApcState
;
550 Thread
->ApcStatePointer
[AttachedApcEnvironment
] = &Thread
->SavedApcState
;
551 Thread
->ApcStateIndex
= OriginalApcEnvironment
;
554 KiReleaseApcLockFromDpcLevel(&ApcLock
);
557 KiSwapProcess(Thread
->ApcState
.Process
, Thread
->ApcState
.Process
);
559 /* Exit the dispatcher */
560 KiExitDispatcher(ApcLock
.OldIrql
);
562 /* Check if we have pending APCs */
563 if (IsListEmpty(&Thread
->ApcState
.ApcListHead
[KernelMode
]))
565 /* What do you know, we do! Request them to be delivered */
566 Thread
->ApcState
.KernelApcPending
= TRUE
;
567 HalRequestSoftwareInterrupt(APC_LEVEL
);
576 KeIsAttachedProcess(VOID
)
578 /* Return the APC State */
579 return KeGetCurrentThread()->ApcStateIndex
;
587 KeStackAttachProcess(IN PKPROCESS Process
,
588 OUT PRKAPC_STATE ApcState
)
590 KLOCK_QUEUE_HANDLE ApcLock
;
591 PKTHREAD Thread
= KeGetCurrentThread();
592 ASSERT_PROCESS(Process
);
593 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
595 /* Make sure that we are in the right page directory */
596 UpdatePageDirs(Thread
, Process
);
598 /* Crash system if DPC is being executed! */
599 if (KeIsExecutingDpc())
601 /* Executing a DPC, crash! */
602 KEBUGCHECKEX(INVALID_PROCESS_ATTACH_ATTEMPT
,
604 (ULONG_PTR
)Thread
->ApcState
.Process
,
605 Thread
->ApcStateIndex
,
609 /* Check if we are already in the target process */
610 if (Thread
->ApcState
.Process
== Process
)
612 /* Set magic value so we don't crash later when detaching */
613 ApcState
->Process
= (PKPROCESS
)1;
617 /* Acquire APC Lock */
618 KiAcquireApcLock(Thread
, &ApcLock
);
620 /* Acquire dispatcher lock */
621 KiAcquireDispatcherLockAtDpcLevel();
623 /* Check if the Current Thread is already attached */
624 if (Thread
->ApcStateIndex
!= OriginalApcEnvironment
)
626 /* We're already attached, so save the APC State into what we got */
627 KiAttachProcess(Thread
, Process
, &ApcLock
, ApcState
);
631 /* We're not attached, so save the APC State into SavedApcState */
632 KiAttachProcess(Thread
, Process
, &ApcLock
, &Thread
->SavedApcState
);
633 ApcState
->Process
= NULL
;
642 KeUnstackDetachProcess(IN PRKAPC_STATE ApcState
)
644 KLOCK_QUEUE_HANDLE ApcLock
;
645 PKTHREAD Thread
= KeGetCurrentThread();
647 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
649 /* Check for magic value meaning we were already in the same process */
650 if (ApcState
->Process
== (PKPROCESS
)1) return;
652 /* Loop to make sure no APCs are pending */
655 /* Acquire APC Lock */
656 KiAcquireApcLock(Thread
, &ApcLock
);
658 /* Check if a kernel APC is pending */
659 if (Thread
->ApcState
.KernelApcPending
)
661 /* Check if kernel APC should be delivered */
662 if (!(Thread
->KernelApcDisable
) && (ApcLock
.OldIrql
<= APC_LEVEL
))
664 /* Release the APC lock so that the APC can be delivered */
665 KiReleaseApcLock(&ApcLock
);
670 /* Otherwise, break out */
675 * Check if the process isn't attacked, or has a Kernel APC in progress
676 * or has pending APC of any kind.
678 if ((Thread
->ApcStateIndex
== OriginalApcEnvironment
) ||
679 (Thread
->ApcState
.KernelApcInProgress
) ||
680 (!IsListEmpty(&Thread
->ApcState
.ApcListHead
[KernelMode
])) ||
681 (!IsListEmpty(&Thread
->ApcState
.ApcListHead
[UserMode
])))
683 /* Bugcheck the system */
684 KEBUGCHECK(INVALID_PROCESS_DETACH_ATTEMPT
);
687 /* Get the process */
688 Process
= Thread
->ApcState
.Process
;
690 /* Acquire dispatcher lock */
691 KiAcquireDispatcherLockAtDpcLevel();
693 /* Decrease the stack count */
694 ASSERT(Process
->StackCount
!= 0);
695 ASSERT(Process
->State
== ProcessInMemory
);
696 Process
->StackCount
--;
698 /* Check if we can swap the process out */
699 if (!Process
->StackCount
)
701 /* FIXME: Swap the process out */
704 /* Release dispatcher lock */
705 KiReleaseDispatcherLockFromDpcLevel();
707 /* Check if there's an APC state to restore */
708 if (ApcState
->Process
)
710 /* Restore the APC State */
711 KiMoveApcState(ApcState
, &Thread
->ApcState
);
715 /* The ApcState parameter is useless, so use the saved data and reset it */
716 KiMoveApcState(&Thread
->SavedApcState
, &Thread
->ApcState
);
717 Thread
->SavedApcState
.Process
= NULL
;
718 Thread
->ApcStateIndex
= OriginalApcEnvironment
;
719 Thread
->ApcStatePointer
[OriginalApcEnvironment
] = &Thread
->ApcState
;
720 Thread
->ApcStatePointer
[AttachedApcEnvironment
] = &Thread
->SavedApcState
;
724 KiReleaseApcLockFromDpcLevel(&ApcLock
);
727 KiSwapProcess(Thread
->ApcState
.Process
, Thread
->ApcState
.Process
);
729 /* Exit the dispatcher */
730 KiExitDispatcher(ApcLock
.OldIrql
);
732 /* Check if we have pending APCs */
733 if (IsListEmpty(&Thread
->ApcState
.ApcListHead
[KernelMode
]))
735 /* What do you know, we do! Request them to be delivered */
736 Thread
->ApcState
.KernelApcPending
= TRUE
;
737 HalRequestSoftwareInterrupt(APC_LEVEL
);
746 KeAddSystemServiceTable(IN PULONG_PTR Base
,
747 IN PULONG Count OPTIONAL
,
754 /* Check if descriptor table entry is free */
755 if ((Index
> SSDT_MAX_ENTRIES
- 1) ||
756 (KeServiceDescriptorTable
[Index
].Base
) ||
757 (KeServiceDescriptorTableShadow
[Index
].Base
))
763 /* Initialize the shadow service descriptor table */
764 KeServiceDescriptorTableShadow
[Index
].Base
= Base
;
765 KeServiceDescriptorTableShadow
[Index
].Limit
= Limit
;
766 KeServiceDescriptorTableShadow
[Index
].Number
= Number
;
767 KeServiceDescriptorTableShadow
[Index
].Count
= Count
;
776 KeRemoveSystemServiceTable(IN ULONG Index
)
780 /* Make sure the Index is valid */
781 if (Index
> (SSDT_MAX_ENTRIES
- 1)) return FALSE
;
783 /* Is there a Normal Descriptor Table? */
784 if (!KeServiceDescriptorTable
[Index
].Base
)
786 /* Not with the index, is there a shadow at least? */
787 if (!KeServiceDescriptorTableShadow
[Index
].Base
) return FALSE
;
790 /* Now clear from the Shadow Table. */
791 KeServiceDescriptorTableShadow
[Index
].Base
= NULL
;
792 KeServiceDescriptorTableShadow
[Index
].Number
= NULL
;
793 KeServiceDescriptorTableShadow
[Index
].Limit
= 0;
794 KeServiceDescriptorTableShadow
[Index
].Count
= NULL
;
796 /* Check if we should clean from the Master one too */
799 KeServiceDescriptorTable
[Index
].Base
= NULL
;
800 KeServiceDescriptorTable
[Index
].Number
= NULL
;
801 KeServiceDescriptorTable
[Index
].Limit
= 0;
802 KeServiceDescriptorTable
[Index
].Count
= NULL
;