xref: /reactos/ntoskrnl/ke/amd64/context.c (revision 9452b29c)
1 /*
2  * PROJECT:         ReactOS Kernel
3  * LICENSE:         GPL - See COPYING in the top level directory
4  * PURPOSE:         CONTEXT related functions
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 /* FUNCTIONS *****************************************************************/
16 
17 VOID
18 NTAPI
19 KeContextToTrapFrame(IN PCONTEXT Context,
20                      IN OUT PKEXCEPTION_FRAME ExceptionFrame,
21                      IN OUT PKTRAP_FRAME TrapFrame,
22                      IN ULONG ContextFlags,
23                      IN KPROCESSOR_MODE PreviousMode)
24 {
25     KIRQL OldIrql;
26 
27     /* Make sure we have an amd64 context, then remove the flag */
28     ASSERT(ContextFlags & CONTEXT_AMD64);
29     ContextFlags &= ~CONTEXT_AMD64;
30 
31     /* Do this at APC_LEVEL */
32     OldIrql = KeGetCurrentIrql();
33     if (OldIrql < APC_LEVEL) KeRaiseIrql(APC_LEVEL, &OldIrql);
34 
35     /* Handle integer registers */
36     if (ContextFlags & CONTEXT_INTEGER)
37     {
38         TrapFrame->Rax = Context->Rax;
39         TrapFrame->Rcx = Context->Rcx;
40         TrapFrame->Rdx = Context->Rdx;
41         TrapFrame->Rbp = Context->Rbp;
42         TrapFrame->R8 = Context->R8;
43         TrapFrame->R9 = Context->R9;
44         TrapFrame->R10 = Context->R10;
45         TrapFrame->R11 = Context->R11;
46         if (ExceptionFrame)
47         {
48             ExceptionFrame->Rbx = Context->Rbx;
49             ExceptionFrame->Rsi = Context->Rsi;
50             ExceptionFrame->Rdi = Context->Rdi;
51             ExceptionFrame->R12 = Context->R12;
52             ExceptionFrame->R13 = Context->R13;
53             ExceptionFrame->R14 = Context->R14;
54             ExceptionFrame->R15 = Context->R15;
55         }
56     }
57 
58     /* Handle floating point registers */
59     if (ContextFlags & CONTEXT_FLOATING_POINT)
60     {
61         TrapFrame->MxCsr = Context->MxCsr;
62         TrapFrame->Xmm0 = Context->Xmm0;
63         TrapFrame->Xmm1 = Context->Xmm1;
64         TrapFrame->Xmm2 = Context->Xmm2;
65         TrapFrame->Xmm3 = Context->Xmm3;
66         TrapFrame->Xmm4 = Context->Xmm4;
67         TrapFrame->Xmm5 = Context->Xmm5;
68         if (ExceptionFrame)
69         {
70             ExceptionFrame->Xmm6 = Context->Xmm6;
71             ExceptionFrame->Xmm7 = Context->Xmm7;
72             ExceptionFrame->Xmm8 = Context->Xmm8;
73             ExceptionFrame->Xmm9 = Context->Xmm9;
74             ExceptionFrame->Xmm10 = Context->Xmm10;
75             ExceptionFrame->Xmm11 = Context->Xmm11;
76             ExceptionFrame->Xmm12 = Context->Xmm12;
77             ExceptionFrame->Xmm13 = Context->Xmm13;
78             ExceptionFrame->Xmm14 = Context->Xmm14;
79             ExceptionFrame->Xmm15 = Context->Xmm15;
80         }
81     }
82 
83     /* Handle control registers */
84     if (ContextFlags & CONTEXT_CONTROL)
85     {
86         /* RIP, RSP, EFLAGS */
87         TrapFrame->Rip = Context->Rip;
88         TrapFrame->Rsp = Context->Rsp;
89         TrapFrame->EFlags = Context->EFlags;
90 
91         if ((Context->SegCs & MODE_MASK) == KernelMode)
92         {
93             /* Set valid selectors */
94             TrapFrame->SegCs = KGDT64_R0_CODE;
95             TrapFrame->SegSs = KGDT64_R0_DATA;
96 
97             /* Set valid EFLAGS */
98             TrapFrame->EFlags &= (EFLAGS_USER_SANITIZE | EFLAGS_INTERRUPT_MASK);
99         }
100         else
101         {
102             /* Copy selectors */
103             TrapFrame->SegCs = Context->SegCs;
104             if (TrapFrame->SegCs != (KGDT64_R3_CODE | RPL_MASK))
105             {
106                 TrapFrame->SegCs = (KGDT64_R3_CMCODE | RPL_MASK);
107             }
108 
109             TrapFrame->SegSs = Context->SegSs;
110 
111             /* Set valid EFLAGS */
112             TrapFrame->EFlags &= EFLAGS_USER_SANITIZE;
113             TrapFrame->EFlags |= EFLAGS_INTERRUPT_MASK;
114         }
115     }
116 
117     /* Handle segment selectors */
118     if (ContextFlags & CONTEXT_SEGMENTS)
119     {
120         /* Check if this was a Kernel Trap */
121         if ((Context->SegCs & MODE_MASK) == KernelMode)
122         {
123             /* Set valid selectors */
124             TrapFrame->SegDs = KGDT64_R3_DATA | RPL_MASK;
125             TrapFrame->SegEs = KGDT64_R3_DATA | RPL_MASK;
126             TrapFrame->SegFs = KGDT64_R3_CMTEB | RPL_MASK;
127             TrapFrame->SegGs = KGDT64_R3_DATA | RPL_MASK;
128         }
129         else
130         {
131             /* Copy selectors */
132             TrapFrame->SegDs = Context->SegDs;
133             TrapFrame->SegEs = Context->SegEs;
134             TrapFrame->SegFs = Context->SegFs;
135             TrapFrame->SegGs = Context->SegGs;
136         }
137     }
138 
139     /* Handle debug registers */
140     if (ContextFlags & CONTEXT_DEBUG_REGISTERS)
141     {
142         /* Copy the debug registers */
143         TrapFrame->Dr0 = Context->Dr0;
144         TrapFrame->Dr1 = Context->Dr1;
145         TrapFrame->Dr2 = Context->Dr2;
146         TrapFrame->Dr3 = Context->Dr3;
147         TrapFrame->Dr6 = Context->Dr6;
148         TrapFrame->Dr7 = Context->Dr7;
149 
150         if ((Context->SegCs & MODE_MASK) != KernelMode)
151         {
152             if (TrapFrame->Dr0 > (ULONG64)MmHighestUserAddress)
153                 TrapFrame->Dr0 = 0;
154             if (TrapFrame->Dr1 > (ULONG64)MmHighestUserAddress)
155                 TrapFrame->Dr1 = 0;
156             if (TrapFrame->Dr2 > (ULONG64)MmHighestUserAddress)
157                 TrapFrame->Dr2 = 0;
158             if (TrapFrame->Dr3 > (ULONG64)MmHighestUserAddress)
159                 TrapFrame->Dr3 = 0;
160         }
161     }
162 
163     /* Restore IRQL */
164     if (OldIrql < APC_LEVEL) KeLowerIrql(OldIrql);
165 }
166 
167 VOID
168 NTAPI
169 KeTrapFrameToContext(IN PKTRAP_FRAME TrapFrame,
170                      IN PKEXCEPTION_FRAME ExceptionFrame,
171                      IN OUT PCONTEXT Context)
172 {
173     ULONG ContextFlags;
174     KIRQL OldIrql;
175 
176     /* Do this at APC_LEVEL */
177     OldIrql = KeGetCurrentIrql();
178     if (OldIrql < APC_LEVEL) KeRaiseIrql(APC_LEVEL, &OldIrql);
179 
180     /* Make sure we have an amd64 context, then remove the flag */
181     ContextFlags = Context->ContextFlags;
182     ASSERT(ContextFlags & CONTEXT_AMD64);
183     ContextFlags &= ~CONTEXT_AMD64;
184 
185     /* Handle integer registers */
186     if (ContextFlags & CONTEXT_INTEGER)
187     {
188         Context->Rax = TrapFrame->Rax;
189         Context->Rcx = TrapFrame->Rcx;
190         Context->Rdx = TrapFrame->Rdx;
191         Context->Rbp = TrapFrame->Rbp;
192         Context->R8 = TrapFrame->R8;
193         Context->R9 = TrapFrame->R9;
194         Context->R10 = TrapFrame->R10;
195         Context->R11 = TrapFrame->R11;
196 
197         if (ExceptionFrame)
198         {
199             Context->Rbx = ExceptionFrame->Rbx;
200             Context->Rsi = ExceptionFrame->Rsi;
201             Context->Rdi = ExceptionFrame->Rdi;
202             Context->R12 = ExceptionFrame->R12;
203             Context->R13 = ExceptionFrame->R13;
204             Context->R14 = ExceptionFrame->R14;
205             Context->R15 = ExceptionFrame->R15;
206         }
207     }
208 
209     /* Handle floating point registers */
210     if (ContextFlags & CONTEXT_FLOATING_POINT)
211     {
212         Context->MxCsr = TrapFrame->MxCsr;
213         Context->Xmm0 = TrapFrame->Xmm0;
214         Context->Xmm1 = TrapFrame->Xmm1;
215         Context->Xmm2 = TrapFrame->Xmm2;
216         Context->Xmm3 = TrapFrame->Xmm3;
217         Context->Xmm4 = TrapFrame->Xmm4;
218         Context->Xmm5 = TrapFrame->Xmm5;
219         if (ExceptionFrame)
220         {
221             Context->Xmm6 = ExceptionFrame->Xmm6;
222             Context->Xmm7 = ExceptionFrame->Xmm7;
223             Context->Xmm8 = ExceptionFrame->Xmm8;
224             Context->Xmm9 = ExceptionFrame->Xmm9;
225             Context->Xmm10 = ExceptionFrame->Xmm10;
226             Context->Xmm11 = ExceptionFrame->Xmm11;
227             Context->Xmm12 = ExceptionFrame->Xmm12;
228             Context->Xmm13 = ExceptionFrame->Xmm13;
229             Context->Xmm14 = ExceptionFrame->Xmm14;
230             Context->Xmm15 = ExceptionFrame->Xmm15;
231         }
232     }
233 
234     /* Handle control registers */
235     if (ContextFlags & CONTEXT_CONTROL)
236     {
237         /* Check if this was a Kernel Trap */
238         if ((TrapFrame->SegCs & MODE_MASK) == KernelMode)
239         {
240             /* Set valid selectors */
241             Context->SegCs = KGDT64_R0_CODE;
242             Context->SegSs = KGDT64_R0_DATA;
243         }
244         else
245         {
246             /* Copy selectors */
247             Context->SegCs = TrapFrame->SegCs;
248             Context->SegSs = TrapFrame->SegSs;
249         }
250 
251         /* Copy RIP, RSP, EFLAGS */
252         Context->Rip = TrapFrame->Rip;
253         Context->Rsp = TrapFrame->Rsp;
254         Context->EFlags = TrapFrame->EFlags;
255     }
256 
257     /* Handle segment selectors */
258     if (ContextFlags & CONTEXT_SEGMENTS)
259     {
260         /* Check if this was a Kernel Trap */
261         if ((TrapFrame->SegCs & MODE_MASK) == KernelMode)
262         {
263             /* Set valid selectors */
264             Context->SegDs = KGDT64_R3_DATA | RPL_MASK;
265             Context->SegEs = KGDT64_R3_DATA | RPL_MASK;
266             Context->SegFs = KGDT64_R3_CMTEB | RPL_MASK;
267             Context->SegGs = KGDT64_R3_DATA | RPL_MASK;
268         }
269         else
270         {
271             /* Copy selectors */
272             Context->SegDs = TrapFrame->SegDs;
273             Context->SegEs = TrapFrame->SegEs;
274             Context->SegFs = TrapFrame->SegFs;
275             Context->SegGs = TrapFrame->SegGs;
276         }
277     }
278 
279     /* Handle debug registers */
280     if (ContextFlags & CONTEXT_DEBUG_REGISTERS)
281     {
282         /* Copy the debug registers */
283         Context->Dr0 = TrapFrame->Dr0;
284         Context->Dr1 = TrapFrame->Dr1;
285         Context->Dr2 = TrapFrame->Dr2;
286         Context->Dr3 = TrapFrame->Dr3;
287         Context->Dr6 = TrapFrame->Dr6;
288         Context->Dr7 = TrapFrame->Dr7;
289     }
290 
291     /* Restore IRQL */
292     if (OldIrql < APC_LEVEL) KeLowerIrql(OldIrql);
293 }
294 
295 VOID
296 RtlSetUnwindContext(
297     _In_ PCONTEXT Context,
298     _In_ DWORD64 TargetFrame);
299 
300 VOID
301 KiSetTrapContextInternal(
302     _Out_ PKTRAP_FRAME TrapFrame,
303     _In_ PCONTEXT Context,
304     _In_ KPROCESSOR_MODE RequestorMode)
305 {
306     ULONG64 TargetFrame;
307 
308     /* Save the volatile register context in the trap frame */
309     KeContextToTrapFrame(Context,
310                          NULL,
311                          TrapFrame,
312                          Context->ContextFlags,
313                          RequestorMode);
314 
315     /* The target frame is MAX_SYSCALL_PARAM_SIZE bytes before the trap frame */
316     TargetFrame = (ULONG64)TrapFrame - MAX_SYSCALL_PARAM_SIZE ;
317 
318     /* Set the nonvolatiles on the stack */
319     RtlSetUnwindContext(Context, TargetFrame);
320 }
321