KiFastCallEntry

 PUBLIC _KiFastCallEntry
_KiFastCallEntry        proc

 

;此时:
;eax指向服务编号
;edx指向当前用户栈,edx+8为参数列表

;
; Sanitize the segment registers
;
        mov     ecx, KGDT_R3_DATA OR RPL_MASK    
        push    KGDT_R0_PCR
        pop     fs              ;fs指向pcr
        mov     ds, ecx     ;ds指向用户数据段
        mov     es, ecx     ;ex指向用户数据段

;
; When we trap into the kernel via fast system call we start on the DPC stack. We need
; shift to the threads stack before enabling interrupts.
;

;其实sysenter操作SYSENTRY_ESP_MSR这个寄存器把它的值存入esp没什么用(SYSENTRY_ESP_MSR在初始化时指向

;prcb的DcpStack
        mov     ecx, PCR[PcTss]        ;从pcr中取得tts
        mov     esp, [ecx]+TssEsp    ;从tts中获得当前线程堆栈的esp

        push    KGDT_R3_DATA OR RPL_MASK   ; Push user SS(压入用户态线程的堆栈段寄存器ss)
        push    edx                         ; Push ESP(压入esp)
        pushfd                                ;压入标志寄存器(eflags)
Kfsc10:
        push    2                           ; Sanitize eflags, clear direction, NT etc;设置eflags为2,,表示所有标志位都是0(中断被关闭)
        add     edx, 8                      ; (edx) -> arguments(移动栈顶指针到参数)
        popfd                               ;
.errnz(EFLAGS_INTERRUPT_MASK AND 0FFFF00FFh)
        or      byte ptr [esp+1], EFLAGS_INTERRUPT_MASK/0100h ; Enable interrupts in eflags(打开用户态eflags的中断)

        push    KGDT_R3_CODE OR RPL_MASK    ; Push user CS
        push    dword ptr ds:[USER_SHARED_DATA+UsSystemCallReturn] ; push return address(使其返回时指向用户空间

;的KiFastSystemCallRet
        push    0                           ; put pad dword for error on stack
        push    ebp                         ; save the non-volatile registers
        push    ebx                         ;
        push    esi                         ;
        push    edi                         ;保存现场
        mov     ebx, PCR[PcSelfPcr]         ; Get PRCB address(获得prcb地址)
        push    KGDT_R3_TEB OR RPL_MASK     ; Push user mode FS
        mov     esi, [ebx].PcPrcbData+PbCurrentThread   ; get current thread address(使esi指向当前线程的KTHREAD)

;
; Save the old exception list in trap frame and initialize a new empty
; exception list.
;

        push    [ebx].PcExceptionList       ; save old exception list(保存老的ExceptionList)
        mov     [ebx].PcExceptionList, EXCEPTION_CHAIN_END ; set new empty list(新的ExceptionList为空白)
        mov     ebp, [esi].ThInitialStack    ;使ebp指向当前线程堆栈的栈顶

;
; Save the old previous mode in trap frame, allocate remainder of trap frame,
; and set the new previous mode.
;
        push    MODE_MASK                  ; Save previous mode as user(保存先前模式)
        sub     esp,TsPreviousPreviousMode ; allocate remainder of trap frame(分配了48h字节, 也就是DbgEbp到Eax所占据的空间

        sub     ebp, NPX_FRAME_LENGTH + KTRAP_FRAME_LENGTH
        mov     byte ptr [esi].ThPreviousMode,MODE_MASK ; set new previous mode of user;设置ETHREAD

;中的PREVIOUSMode为UserMode

;
; Now the full trap frame is build.
; Calculate initial stack pointer from thread initial stack to contain NPX and trap.
; If this isn't the same as esp then we are a VX86 thread and we are rejected
;

        cmp     ebp, esp     ;判断堆栈内压入的值是否正确(这些堆栈内压入的东西,就好比一个trap框架)
        jne     short Kfsc91    ;不正确跳转

;
; Set the new trap frame address.
;
        and     dword ptr [ebp].TsDr7, 0
        test    byte ptr [esi].ThDebugActive, 0ffh ; See if we need to save debug registers
        mov     [esi].ThTrapFrame, ebp   ; set new trap frame address(在ETHREAD中设置自陷框架地址)

        jnz     Dr_FastCallDrSave       ; if nz, debugging is active on thread

Dr_FastCallDrReturn:                       ;

        SET_DEBUG_DATA                  ; Note this destroys edi
        sti                             ; enable interrupts(开中断)

?FpoValue = 0

;

;到这里TRAP_FRAME,开始调用系统服务的准备工作
; (eax) = Service number      ;系统服务序号
; (edx) = Callers stack pointer      ;参数指针
; (esi) = Current thread address       ;线程ETHREAD
;
; All other registers have been saved and are free.
;
; Check if the service number within valid range

;判断系统服务号是否合法
;

_KiSystemServiceRepeat:
        mov     edi, eax                ; copy system service number
        shr     edi, SERVICE_TABLE_SHIFT ; isolate service table number
        and     edi, SERVICE_TABLE_MASK ;
        mov     ecx, edi                ; save service table number
        add     edi, [esi]+ThServiceTable ; compute service descriptor address
        mov     ebx, eax                ; save system service number
        and     eax, SERVICE_NUMBER_MASK ; isolate service table offset

;
; If the specified system service number is not within range, then attempt
; to convert the thread to a GUI thread and retry the service dispatch.

;如果系统服务号不合法,就调用GUI(win32k.sys,sssdt)
;

        cmp     eax, [edi]+SdLimit      ; check if valid service
        jae     Kss_ErrorHandler        ; if ae, try to convert to GUI thread

;
; If the service is a GUI service and the GDI user batch queue is not empty,
; then call the appropriate service to flush the user batch.
;

        cmp     ecx, SERVICE_TABLE_TEST ; test if GUI service
        jne     short Kss40             ; if ne, not GUI service(如果不是GUI跳走)
        mov     ecx, PCR[PcTeb]         ; get current thread TEB address(获得TEB)
        xor     ebx, ebx                ; get number of batched GDI calls

KiSystemServiceAccessTeb:
        or      ebx, [ecx]+TbGdiBatchCount ; may cause an inpage exception(是否有异常)

        jz      short Kss40             ; if z, no batched calls(有,跳走)
        push    edx                     ; save address of user arguments
        push    eax                     ; save service number
        call    [_KeGdiFlushUserBatch]  ; flush GDI user batch
        pop     eax                     ; restore service number
        pop     edx                     ; restore address of user arguments

;
; The arguments are passed on the stack. Therefore they always need to get
; copied since additional space has been allocated on the stack for the
; machine state frame.  Note that we don't check for the zero argument case -
; copy is always done regardless of the number of arguments because the
; zero argument case is very rare.
;

;复制R3的参数到R0的堆栈上

Kss40:  inc     dword ptr PCR[PcPrcbData+PbSystemCalls] ; system calls

if DBG

        mov     ecx, [edi]+SdCount      ; get count table address
        jecxz   short @f                ; if zero, table not specified
        inc     dword ptr [ecx+eax*4]   ; increment service count
@@:                                     ;

endif

FPOFRAME ?FpoValue, 0

        mov     esi, edx                ; (esi)->User arguments
        mov     ebx, [edi]+SdNumber     ; get argument table address
        xor     ecx, ecx
        mov     cl, byte ptr [ebx+eax]  ; (ecx) = argument size
        mov     edi, [edi]+SdBase       ; get service table address
        mov     ebx, [edi+eax*4]        ; (ebx)-> service routine
        sub     esp, ecx                ; allocate space for arguments
        shr     ecx, 2                  ; (ecx) = number of argument DWORDs
        mov     edi, esp                ; (edi)->location to receive 1st arg
        cmp     esi, _MmUserProbeAddress ; check if user address
        jae     kss80                   ; if ae, then not user address

KiSystemServiceCopyArguments:          ;向ring0堆栈中拷贝参数起始于标号
        rep     movsd                   ; copy the arguments to top of stack.
                                        ; Since we usually copy more than 3
                                        ; arguments.  rep movsd is faster than
                                        ; mov instructions.

;
; Check if low resource usage should be simulated.
;

if DBG

        test    _MmInjectUserInpageErrors, 2
        jz      short @f
        stdCall _MmTrimProcessMemory, <0>
        jmp     short kssdoit
@@:

        mov     eax,PCR[PcPrcbData+PbCurrentThread]
        mov     eax,[eax]+ThApcState+AsProcess
        test    dword ptr [eax]+PrFlags,0100000h ; is this a inpage-err process?
        je      short @f
        stdCall _MmTrimProcessMemory, <0>
@@:

endif

;
; Make actual call to system service
;

kssdoit:
        call    ebx                     ; call system service

kss60:

;
; Check for return to user mode at elevated IRQL.
;

if DBG

        test    byte ptr [ebp]+TsSegCs,MODE_MASK ; test if previous mode user
        jz      short kss50b            ; if z, previous mode not user
        mov     esi,eax                 ; save return status
        CurrentIrql                     ; get current IRQL
        or      al,al                   ; check if IRQL is passive level
        jnz     kss100                  ; if nz, IRQL not passive level
        mov     eax,esi                 ; restore return status

;
; Check if kernel APCs are disabled or a process is attached.
;
       
        mov     ecx,PCR[PcPrcbData+PbCurrentThread] ; get current thread address
        mov     dl,[ecx]+ThApcStateIndex ; get APC state index
        or      dl,dl                   ; check if process attached
        jne     kss120                  ; if ne, process is attached
        mov     edx,[ecx]+ThCombinedApcDisable ; get kernel APC disable
        or      edx,edx                 ; check if kernel APCs disabled
        jne     kss120                  ; if ne, kernel APCs disabled.
kss50b:                                 ;

endif

kss61:

;
; Upon return, (eax)= status code. This code may also be entered from a failed
; KiCallbackReturn call.
;

        mov     esp, ebp                ; deallocate stack space for arguments

;
; Restore old trap frame address from the current trap frame.
;

kss70:  mov     ecx, PCR[PcPrcbData+PbCurrentThread] ; get current thread address
        mov     edx, [ebp].TsEdx        ; restore previous trap frame address
        mov     [ecx].ThTrapFrame, edx  ;

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值