xref: /reactos/ntoskrnl/ke/amd64/stubs.c (revision 864aed6b)
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 /* GLOBALS *******************************************************************/
16 
17 ULONG ProcessCount;
18 SIZE_T KeXStateLength = sizeof(XSAVE_FORMAT);
19 
20 PVOID
21 KiSwitchKernelStackHelper(
22     LONG_PTR StackOffset,
23     PVOID OldStackBase);
24 
25 /*
26  * Kernel stack layout (example pointers):
27  * 0xFFFFFC0F'2D008000 KTHREAD::StackBase
28  *    [XSAVE_AREA size == KeXStateLength = 0x440]
29  * 0xFFFFFC0F'2D007BC0 KTHREAD::StateSaveArea _XSAVE_FORMAT
30  * 0xFFFFFC0F'2D007B90 KTHREAD::InitialStack
31  *    [0x190 bytes KTRAP_FRAME]
32  * 0xFFFFFC0F'2D007A00 KTHREAD::TrapFrame
33  *    [KSTART_FRAME] or ...
34  *    [KSWITCH_FRAME]
35  * 0xFFFFFC0F'2D007230 KTHREAD::KernelStack
36  */
37 
38 PVOID
39 NTAPI
40 KiSwitchKernelStack(PVOID StackBase, PVOID StackLimit)
41 {
42     PKTHREAD CurrentThread;
43     PVOID OldStackBase;
44     LONG_PTR StackOffset;
45     SIZE_T StackSize;
46     PKIPCR Pcr;
47     ULONG Eflags;
48 
49     /* Get the current thread */
50     CurrentThread = KeGetCurrentThread();
51 
52     /* Save the old stack base */
53     OldStackBase = CurrentThread->StackBase;
54 
55     /* Get the size of the current stack */
56     StackSize = (ULONG_PTR)CurrentThread->StackBase - CurrentThread->StackLimit;
57     ASSERT(StackSize <= (ULONG_PTR)StackBase - (ULONG_PTR)StackLimit);
58 
59     /* Copy the current stack contents to the new stack */
60     RtlCopyMemory((PUCHAR)StackBase - StackSize,
61                   (PVOID)CurrentThread->StackLimit,
62                   StackSize);
63 
64     /* Calculate the offset between the old and the new stack */
65     StackOffset = (PUCHAR)StackBase - (PUCHAR)CurrentThread->StackBase;
66 
67     /* Disable interrupts while messing with the stack */
68     Eflags = __readeflags();
69     _disable();
70 
71     /* Set the new trap frame */
72     CurrentThread->TrapFrame = (PKTRAP_FRAME)Add2Ptr(CurrentThread->TrapFrame,
73                                                      StackOffset);
74 
75     /* Set the new initial stack */
76     CurrentThread->InitialStack = Add2Ptr(CurrentThread->InitialStack,
77                                           StackOffset);
78 
79     /* Set the new stack limits */
80     CurrentThread->StackBase = StackBase;
81     CurrentThread->StackLimit = (ULONG_PTR)StackLimit;
82     CurrentThread->LargeStack = TRUE;
83 
84     /* Adjust RspBase in the PCR */
85     Pcr = (PKIPCR)KeGetPcr();
86     Pcr->Prcb.RspBase += StackOffset;
87 
88     /* Adjust Rsp0 in the TSS */
89     Pcr->TssBase->Rsp0 += StackOffset;
90 
91     /* Restore interrupts */
92     __writeeflags(Eflags);
93 
94     return OldStackBase;
95 }
96 
97 DECLSPEC_NORETURN
98 VOID
99 KiIdleLoop(VOID)
100 {
101     PKPRCB Prcb = KeGetCurrentPrcb();
102     PKTHREAD OldThread, NewThread;
103 
104     /* Now loop forever */
105     while (TRUE)
106     {
107         /* Start of the idle loop: disable interrupts */
108         _enable();
109         YieldProcessor();
110         YieldProcessor();
111         _disable();
112 
113         /* Check for pending timers, pending DPCs, or pending ready threads */
114         if ((Prcb->DpcData[0].DpcQueueDepth) ||
115             (Prcb->TimerRequest) ||
116             (Prcb->DeferredReadyListHead.Next))
117         {
118             /* Quiesce the DPC software interrupt */
119             HalClearSoftwareInterrupt(DISPATCH_LEVEL);
120 
121             /* Handle it */
122             KiRetireDpcList(Prcb);
123         }
124 
125         /* Check if a new thread is scheduled for execution */
126         if (Prcb->NextThread)
127         {
128             /* Enable interrupts */
129             _enable();
130 
131             /* Capture current thread data */
132             OldThread = Prcb->CurrentThread;
133             NewThread = Prcb->NextThread;
134 
135             /* Set new thread data */
136             Prcb->NextThread = NULL;
137             Prcb->CurrentThread = NewThread;
138 
139             /* The thread is now running */
140             NewThread->State = Running;
141 
142 #ifdef CONFIG_SMP
143             /* Do the swap at SYNCH_LEVEL */
144             KfRaiseIrql(SYNCH_LEVEL);
145 #endif
146 
147             /* Switch away from the idle thread */
148             KiSwapContext(APC_LEVEL, OldThread);
149 
150 #ifdef CONFIG_SMP
151             /* Go back to DISPATCH_LEVEL */
152             KeLowerIrql(DISPATCH_LEVEL);
153 #endif
154         }
155         else
156         {
157             /* Continue staying idle. Note the HAL returns with interrupts on */
158             Prcb->PowerState.IdleFunction(&Prcb->PowerState);
159         }
160     }
161 }
162 
163 VOID
164 NTAPI
165 KiSwapProcess(IN PKPROCESS NewProcess,
166               IN PKPROCESS OldProcess)
167 {
168     PKIPCR Pcr = (PKIPCR)KeGetPcr();
169 
170 #ifdef CONFIG_SMP
171     /* Update active processor mask */
172     InterlockedXor64((PLONG64)&NewProcess->ActiveProcessors, Pcr->Prcb.SetMember);
173     InterlockedXor64((PLONG64)&OldProcess->ActiveProcessors, Pcr->Prcb.SetMember);
174 #endif
175 
176     /* Update CR3 */
177     __writecr3(NewProcess->DirectoryTableBase[0]);
178 
179     /* Update IOPM offset */
180     Pcr->TssBase->IoMapBase = NewProcess->IopmOffset;
181 }
182 
183 NTSTATUS
184 NTAPI
185 NtSetLdtEntries(ULONG Selector1, LDT_ENTRY LdtEntry1, ULONG Selector2, LDT_ENTRY LdtEntry2)
186 {
187     UNIMPLEMENTED;
188     __debugbreak();
189     return STATUS_UNSUCCESSFUL;
190 }
191 
192 NTSTATUS
193 NTAPI
194 NtVdmControl(IN ULONG ControlCode,
195              IN PVOID ControlData)
196 {
197     /* Not supported */
198     return STATUS_NOT_IMPLEMENTED;
199 }
200