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