diff options
Diffstat (limited to 'private/ntos/ke/i386/callout.asm')
-rw-r--r-- | private/ntos/ke/i386/callout.asm | 432 |
1 files changed, 432 insertions, 0 deletions
diff --git a/private/ntos/ke/i386/callout.asm b/private/ntos/ke/i386/callout.asm new file mode 100644 index 000000000..69e484f17 --- /dev/null +++ b/private/ntos/ke/i386/callout.asm @@ -0,0 +1,432 @@ + title "Call Out to User Mode" +;++ +; +; Copyright (c) 1994 Microsoft Corporation +; +; Module Name: +; +; callout.asm +; +; Abstract: +; +; This module implements the code necessary to call out from kernel +; mode to user mode. +; +; Author: +; +; David N. Cutler (davec) 1-Nov-1994 +; +; Environment: +; +; Kernel mode only. +; +; Revision History: +; +;-- + +.386p + .xlist +include ks386.inc +include i386\kimacro.inc +include callconv.inc + .list + + extrn _KiServiceExit:PROC + extrn _KeUserCallbackDispatcher:DWORD + + EXTRNP _MmGrowKernelStack,1 + +_TEXT SEGMENT DWORD PUBLIC 'CODE' + ASSUME DS:FLAT, ES:FLAT, SS:FLAT, FS:NOTHING, GS:NOTHING + + page ,132 + subttl "Call User Mode Function" +;++ +; +; NTSTATUS +; KiCallUserMode ( +; IN PVOID *Outputbuffer, +; IN PULONG OutputLength +; ) +; +; Routine Description: +; +; This function calls a user mode function from kernel mode. +; +; N.B. This function calls out to user mode and the NtCallbackReturn +; function returns back to the caller of this function. Therefore, +; the stack layout must be consistent between the two routines. +; +; Arguments: +; +; OutputBuffer - Supplies a pointer to the variable that receivies +; the address of the output buffer. +; +; OutputLength - Supplies a pointer to a variable that receives +; the length of the output buffer. +; +; Return Value: +; +; The final status of the call out function is returned as the status +; of the function. +; +; N.B. This function does not return to its caller. A return to the +; caller is executed when a NtCallbackReturn system service is +; executed. +; +; N.B. This function does return to its caller if a kernel stack +; expansion is required and the attempted expansion fails. +; +;-- + +; +; To support the debugger, the callback stack frame is now defined in i386.h. +; If the stack frame is changed, i386.h must be updated and geni386 +; rebuilt and run, then rebuild this file and ntos\kd. +; +; The FPO record below must also be updated to correctly represent +; the stack frame. +; + +cPublicProc _KiCallUserMode, 2 + +.FPO (3, 2, 4, 4, 0, 0) + +; +; Save nonvolatile registers. +; + + push ebp ; save nonvolatile registers + push ebx ; + push esi ; + push edi ; + +; +; Check if sufficient room is available on the kernel stack for another +; system call. +; + + mov ebx,PCR[PcPrcbData + PbCurrentThread] ; get current thread address + lea eax,[esp]-KERNEL_LARGE_STACK_COMMIT ; compute bottom address + cmp eax,[ebx]+ThStackLimit ; check if limit exceeded + jae short Kcb10 ; if ae, limit not exceeded + stdCall _MmGrowKernelStack,<esp> ; attempt to grow kernel stack + or eax, eax ; check for successful completion + jne Kcb20 ; if ne, attempt to grow failed + mov eax, [ebx].ThStackLimit ; get new stack limit + mov PCR[PcStackLimit], eax ; set new stack limit + +; +; Get the address of the current thread and save the previous trap frame +; and calback stack addresses in the current frame. Also save the new +; callback stack address in the thread object. +; + +Kcb10: push [ebx].ThCallbackStack ; save callback stack address + mov edx,[ebx].ThTrapFrame ; get current trap frame address + push edx ; save trap frame address + mov esi,[ebx].ThInitialStack ; get initial stack address + push esi ; save initial stack address + mov [ebx].ThCallbackStack,esp ; save callback stack address + +KcbPrologEnd: ; help for the debugger + +; +; Copy the numeric save area from the previous save area to the new save +; area and establish a new initial kernel stack. +; + + mov edi,esp ; set new initial stack address + sub esp,NPX_FRAME_LENGTH ; compute destination NPX save area + sub esi,NPX_FRAME_LENGTH ; compute source NPX save area + cli ; disable interrupts + mov ecx,[esi].FpControlWord ; copy NPX state to new frame + mov [esp].FpControlWord,ecx ; + mov ecx,[esi].FpStatusWord ; + mov [esp].FpStatusWord,ecx ; + mov ecx,[esi].FpTagWord ; + mov [esp].FpTagWord,ecx ; + mov ecx,[esi].FpCr0NpxState ; + mov [esp].FpCr0NpxState,ecx ; + mov esi,PCR[PcTss] ; get address of task switch segment + mov [ebx].ThInitialStack,edi ; reset initial stack address + mov PCR[PcInitialStack],esp ; set stack check base address + sub esp,TsV86Gs - TsHardwareSegSs ; bias for missing V86 fields + mov [esi].TssEsp0,esp ; set kernel entry stack address + +; +; Construct a trap frame to facilitate the transfer into user mode via +; the standard system call exit. +; + + sub esp,TsHardwareSegSs + 4 ; allocate trap frame + mov ebp,esp ; set address of trap frame + mov ecx,(TsHardwareSegSs - TsSegFs + 4) / 4; set repeat count + lea edi,[esp].TsSegFs ; set destination address + lea esi,[edx].TsSegFs ; set source address + rep movsd ; copy trap information + + test byte ptr [ebx]+ThDebugActive, -1 ; Do we need to restore Debug reg? + jnz short Kcb18 ; Yes, go save them. + +Kcb15: mov eax,_KeUserCallbackDispatcher ; st address of callback dispatchr + mov [esp].TsEip,eax ; + mov eax,PCR[PcExceptionList] ; get current exception list + mov [esp].TsExceptionList,eax ; set previous exception list + mov eax,[edx].TsPreviousPreviousMode ; get previous mode + mov [esp].TsPreviousPreviousMode,eax ; set previous mode + sti ; enable interrupts + + SET_DEBUG_DATA ; set system call debug data for exit + + jmp _KiServiceExit ; exit through service dispatch + +Kcb18: + mov ecx,(TsDr7 - TsDr0 + 4) / 4; set repeat count + lea edi,[esp].TsDr0 ; set destination address + lea esi,[edx].TsDr0 ; set source address + rep movsd ; copy trap information + jmp short Kcb15 + +; +; An attempt to grow the kernel stack failed. +; + +Kcb20: pop edi ; restore nonvolitile register + pop esi ; + pop ebx ; + pop ebp ; + stdRET _KiCallUserMode + +stdENDP _KiCallUserMode + + page ,132 + subttl "Switch Kernel Stack" +;++ +; +; PVOID +; KeSwitchKernelStack ( +; IN PVOID StackBase, +; IN PVOID StackLimit +; ) +; +; Routine Description: +; +; This function switches to the specified large kernel stack. +; +; N.B. This function can ONLY be called when there are no variables +; in the stack that refer to other variables in the stack, i.e., +; there are no pointers into the stack. +; +; Arguments: +; +; StackBase (esp + 4) - Supplies a pointer to the base of the new kernel +; stack. +; +; StackLimit (esp + 8) - Suplies a pointer to the limit of the new kernel +; stack. +; +; Return Value: +; +; The old kernel stack is returned as the function value. +; +;-- + +SsStkBs equ 4 ; new kernel stack base address +SsStkLm equ 8 ; new kernel stack limit address + +cPublicProc _KeSwitchKernelStack, 2 + +; +; Save the address of the new stack and copy the old stack to the new +; stack. +; + + push esi ; save string move registers + push edi ; + mov edx,PCR[PcPrcbData + PbCurrentThread] ; get current thread address + mov edi,[esp]+SsStkBs + 8 ; get new kernel stack base address + mov ecx,[edx].ThStackBase ; get current stack base address + sub ebp,ecx ; relocate the callers frame pointer + add ebp,edi ; + mov eax,[edx].ThTrapFrame ; relocate the current trap frame address + sub eax,ecx ; + add eax,edi ; + mov [edx].ThTrapFrame,eax ; + sub ecx,esp ; compute length of copy + sub edi,ecx ; set destination address of copy + mov esi,esp ; set source address of copy + push edi ; save new stack pointer address + rep movsb ; copy old stack to new stack + pop edi ; restore new stack pointer address + +; +; Switch to the new kernel stack and return the address of the old kernel +; stack. +; + + mov eax,[edx].ThStackBase ; get old kernel stack base address + mov ecx,[esp]+SsStkBs + 8 ; get new kernel stack base address + mov esi,[esp]+SsStkLm + 8 ; get new kernel stack limit address + cli ; disable interrupts + mov [edx].ThStackBase,ecx ; set new kernel stack base address + mov [edx].ThStackLimit,esi ; set new kernel stack limit address + mov byte ptr [edx].ThLargeStack, 1 ; set large stack TRUE + mov [edx].ThInitialStack,ecx ; set new initial stack address + sub ecx,NPX_FRAME_lENGTH ; compute NPX save area address + mov PCR[PcInitialStack],ecx ; set stack check base address + mov PCR[PcStackLimit],esi ; set stack check limit address + mov edx,PCR[PcTss] ; get address of task switch segment + sub ecx,TsV86Gs - TsHardwareSegSs ; bias for missing V86 fields + mov [edx].TssEsp0,ecx ; set kernel entry stack address + mov esp,edi ; set new stack pointer address + sti ; + pop edi ; restore string move registers + pop esi ; + stdRET _KeSwitchKernelStack + +stdENDP _KeSwitchKernelStack + + page ,132 + subttl "Get User Mode Stack Address" +;++ +; +; PULONG +; KiGetUserModeStackAddress ( +; VOID +; ) +; +; Routine Description: +; +; This function returns the address of the user stack address in the +; current trap frame. +; +; Arguments: +; +; None. +; +; Return Value: +; +; The address of the user stack address. +; +;-- + +cPublicProc _KiGetUserModeStackAddress, 0 + + mov eax,PCR[PcPrcbData + PbCurrentThread] ; get current thread address + mov eax,[eax].ThTrapFrame ; get current trap frame address + lea eax,[eax].TsHardwareEsp ; get address of stack address + stdRET _KiGetUserModeStackAddress + +stdENDP _KiGetUserModeStackAddress + + page ,132 + subttl "Return from User Mode Callback" +;++ +; +; NTSTATUS +; NtCallbackReturn ( +; IN PVOID OutputBuffer OPTIONAL, +; IN ULONG OutputLength, +; IN NTSTATUS Status +; ) +; +; Routine Description: +; +; This function returns from a user mode callout to the kernel +; mode caller of the user mode callback function. +; +; N.B. This function returns to the function that called out to user +; mode and the KiCallUserMode function calls out to user mode. +; Therefore, the stack layout must be consistent between the +; two routines. +; +; Arguments: +; +; OutputBuffer - Supplies an optional pointer to an output buffer. +; +; OutputLength - Supplies the length of the output buffer. +; +; Status - Supplies the status value returned to the caller of the +; callback function. +; +; Return Value: +; +; If the callback return cannot be executed, then an error status is +; returned. Otherwise, the specified callback status is returned to +; the caller of the callback function. +; +; N.B. This function returns to the function that called out to user +; mode is a callout is currently active. +; +;-- + +cPublicProc _NtCallbackReturn, 3 + + mov eax,PCR[PcPrcbData + PbCurrentThread] ; get current thread address + mov ecx,[eax].ThCallbackStack ; get callback stack address + jecxz short CbExit ; if zero, no callback stack present + +; +; Restore the current exception list from the saved exception list in the +; current trap frame, restore the trap frame and callback stack addresses, +; store the output buffer address and length, and set the service status. +; + + mov ebx,[eax].ThTrapFrame ; get current trap frame address + mov edx,[ebx].TsExceptionList ; get saved exception list address + mov PCR[PcExceptionList],edx ; restore exception list address + mov edi,[esp] + 4 ; get output buffer address + mov esi,[esp] + 8 ; get output buffer length + mov ebp,[esp] + 12 ; get callout service status + mov ebx,[ecx].CuOutBf ; get address to store output buffer + mov [ebx],edi ; store output buffer address + mov ebx,[ecx].CuOutLn ; get address to store output length + mov [ebx],esi ; store output buffer length + cli ; disable interrupt + mov esi,PCR[PcInitialStack] ; get source NPX save area address + mov esp,ecx ; trim stack back to callback frame + pop ecx ; get previous initial stack address + mov [eax].ThInitialStack,ecx ; restore initial stack address + sub ecx,NPX_FRAME_LENGTH ; compute destination NPX save area + mov edx,[esi].FpControlWord ; copy NPX state to previous frame + mov [ecx].FpControlWord,edx ; + mov edx,[esi].FpStatusWord ; + mov [ecx].FpStatusWord,edx ; + mov edx,[esi].FpTagWord ; + mov [ecx].FpTagWord,edx ; + mov edx,[esi].FpCr0NpxState ; + mov [ecx].FpCr0NpxState,edx ; + mov edx,PCR[PcTss] ; get address of task switch segment + mov PCR[PcInitialStack],ecx ; restore stack check base address + sub ecx,TsV86Gs - TsHardwareSegSs ; bias for missing V86 fields + mov [edx].TssEsp0,ecx ; restore kernel entry stack address + sti ; enable interrupts + pop [eax].ThTrapFrame ; restore current trap frame address + pop [eax].ThCallbackStack ; restore callback stack address + mov eax,ebp ; set callback service status + +; +; Restore nonvolatile registers, clean call parameters from stack, and +; return to callback caller. +; + + pop edi ; restore nonvolatile registers + pop esi ; + pop ebx ; + pop ebp ; + pop edx ; save return address + add esp,8 ; remove parameters from stack + jmp edx ; return to callback caller + +; +; No callback is currently active. +; + +CbExit: mov eax,STATUS_NO_CALLBACK_ACTIVE ; set service status + stdRET _NtCallBackReturn + +stdENDP _NtCallbackReturn + +_TEXT ends + end |