xref: /reactos/ntoskrnl/ke/i386/usercall_asm.S (revision 40462c92)
1/*
2 * COPYRIGHT:       See COPYING in the top level directory
3 * PROJECT:         ReactOS Kernel
4 * FILE:            ntoskrnl/ke/i386/usercall_asm.S
5 * PURPOSE:         User-Mode callbacks and return.
6 * PROGRAMMERS:     Alex Ionescu (alex@relsoft.net)
7 */
8
9/* INCLUDES ******************************************************************/
10
11#include <asm.inc>
12#include <ks386.inc>
13#include <internal/i386/asmmacro.S>
14
15EXTERN _MmGrowKernelStack@4:PROC
16EXTERN _KeUserCallbackDispatcher:DWORD
17EXTERN @KiServiceExit@8:PROC
18EXTERN _KeGetCurrentIrql@0:PROC
19EXTERN _KeBugCheckEx@20:PROC
20EXTERN @KiUserModeCallout@4:PROC
21
22/* FUNCTIONS ****************************************************************/
23.code
24
25/*++
26 * @name KiCallUserMode
27 *
28 *     The KiSwitchToUserMode routine sets up a Trap Frame and a Callback stack
29 *     for the purpose of switching to user mode. The actual final jump is done
30 *     by KiServiceExit which will treat this as a syscall return.
31 *
32 * @param OutputBuffer
33 *        Pointer to a caller-allocated buffer where to receive the return data
34 *        from the user-mode function
35 *
36 * @param OutputLength
37 *        Size of the Output Buffer described above.
38 *
39 * @return None. Jumps into KiServiceExit.
40 *
41 * @remark If there is not enough Kernel Stack space, the routine will increase the
42 *         Kernel Stack.
43 *
44 *         User mode execution resumes at ntdll!KiUserCallbackDispatcher.
45 *
46 *         This call MUST be paired by interrupt 0x2B or NtCallbackReturn.
47 *
48 *--*/
49PUBLIC _KiCallUserMode@8
50_KiCallUserMode@8:
51
52    /* Push non-volatile registers on the stack.
53       This is part of the KCALLOUT_FRAME */
54    push ebp
55    push ebx
56    push esi
57    push edi
58
59    /* load the address of the callout frame into ecx */
60    lea ecx, [esp - 12]
61
62    /* Allocate space for the initial stack */
63    sub esp, 12 + NPX_FRAME_LENGTH + KTRAP_FRAME_LENGTH + 16
64
65    call @KiUserModeCallout@4
66
67    add esp, 12 + NPX_FRAME_LENGTH + KTRAP_FRAME_LENGTH + 16
68
69    /* Restore registers */
70    pop edi
71    pop esi
72    pop ebx
73    pop ebp
74
75    /* Return */
76    ret 8
77
78
79
80PUBLIC @KiCallbackReturn@8
81@KiCallbackReturn@8:
82
83    /* Restore the stack */
84    mov esp, ecx
85
86    /* Set status and return */
87    mov eax, edx
88    pop edi
89    pop esi
90    pop ebx
91    pop ebp
92
93    /* Clean stack and return */
94    ret 8
95
96/*++
97 * @name KeSwitchKernelStack
98 *
99 *     The KeSwitchKernelStack routine switches from the current thread's stack
100 *     to the new specified base and limit.
101 *
102 * @param StackBase
103 *        Pointer to the new Stack Base of the thread.
104 *
105 * @param StackLimit
106 *        Pointer to the new Stack Limit of the thread.
107 *
108 * @return The previous Stack Base of the thread.
109 *
110 * @remark This routine should typically only be used when converting from a
111 *         non-GUI to a GUI Thread. The caller is responsible for freeing the
112 *         previous stack. The new stack values MUST be valid before calling
113 *         this routine.
114 *
115 *--*/
116PUBLIC _KeSwitchKernelStack@8
117_KeSwitchKernelStack@8:
118
119    /* Save volatiles */
120    push esi
121    push edi
122
123    /* Get current thread */
124    mov edx, fs:[KPCR_CURRENT_THREAD]
125
126    /* Get new and current base */
127    mov edi, [esp+12]
128    mov ecx, [edx+KTHREAD_STACK_BASE]
129
130    /* Fixup the frame pointer */
131    sub ebp, ecx
132    add ebp, edi
133
134    /* Fixup the trap frame */
135    mov eax, [edx+KTHREAD_TRAP_FRAME]
136    sub eax, ecx
137    add eax, edi
138    mov [edx+KTHREAD_TRAP_FRAME], eax
139
140    /* Calculate stack size */
141    sub ecx, esp
142
143    /* Get desination and origin */
144    sub edi, ecx
145    mov esi, esp
146
147    /* Save stack pointer */
148    push edi
149
150    /* Copy stack */
151    rep movsb
152
153    /* Restore stack pointer */
154    pop edi
155
156    /* Save old stack base and get new limit/base */
157    mov eax, [edx+KTHREAD_STACK_BASE]
158    mov ecx, [esp+12]
159    mov esi, [esp+16]
160
161    /* Disable interrupts for stack switch */
162    cli
163
164    /* Set new base/limit */
165    mov [edx+KTHREAD_STACK_BASE], ecx
166    mov [edx+KTHREAD_STACK_LIMIT], esi
167
168    /* Set LargeStack */
169    mov byte ptr [edx+KTHREAD_LARGE_STACK], 1
170
171    /* Set new initial stack */
172    mov [edx+KTHREAD_INITIAL_STACK], ecx
173
174    /* Get trap frame */
175    mov esi, [edx+KTHREAD_TRAP_FRAME]
176
177    /* Get TSS */
178    mov edx, fs:[KPCR_TSS]
179
180    /* Check if we came from V86 mode */
181    test dword ptr [esi+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
182
183    /* Bias for NPX Area */
184    lea ecx, [ecx-NPX_FRAME_LENGTH]
185    jnz V86Switch
186    sub ecx, 16
187
188V86Switch:
189
190    /* Update ESP in TSS */
191    mov [edx+KTSS_ESP0], ecx
192
193    /* Update stack pointer */
194    mov esp, edi
195
196    /* Bring back interrupts and return */
197    sti
198    pop edi
199    pop esi
200    ret 8
201
202END
203